Gibt es in C++ einen Unterschied zwischen:
struct Foo { ... };
und
typedef struct { ... } Foo;
In C++ gibt es nur einen feinen Unterschied. Es ist ein Überbleibsel aus C, in dem es einen Unterschied macht.
Der C-Sprachstandard (C89 §3.1.2.3, C99 §6.2.3 und C11 §6.2.3) schreibt getrennte Namensräume für verschiedene Kategorien von Bezeichnern vor, darunter tag identifiers (für struct
/union
/enum
) und ordinary identifiers (für typedef
und andere Bezeichner).
Wenn Sie gerade gesagt haben:
struct Foo { ... };
Foo x;
würde man einen Compilerfehler erhalten, da Foo
nur im Tag-Namensraum definiert ist.
Sie müssten es deklarieren als:
struct Foo x;
Jedes Mal, wenn Sie sich auf Foo
beziehen wollen, müssen Sie es immer als struct Foo
bezeichnen. Das wird schnell lästig, also kann man ein typedef
hinzufügen:
struct Foo { ... };
typedef struct Foo Foo;
Jetzt verweisen struct Foo
(im Tag-Namensraum) und einfach nur Foo
(im gewöhnlichen Bezeichner-Namensraum) beide auf dasselbe, und Sie können Objekte vom Typ Foo
ohne das Schlüsselwort struct
deklarieren.
Das Konstrukt:
typedef struct Foo { ... } Foo;
ist nur eine Abkürzung für die Deklaration und typedef
.
Endlich,
typedef struct { ... } Foo;
eine anonyme Struktur deklariert und ein typedef
für sie erstellt. Mit diesem Konstrukt hat sie also keinen Namen im Tag-Namensraum, sondern nur einen Namen im Typedef-Namensraum. Das bedeutet, dass es auch nicht weiterdeklariert werden kann. Wenn Sie eine Vorwärtsdeklaration machen wollen, müssen Sie ihm einen Namen im Tag-Namensraum geben.
In C++ verhalten sich alle struct
/union
/enum
/class
-Deklarationen so, als wären sie implizit typedef
'ed, solange der Name nicht durch eine andere Deklaration mit demselben Namen verdeckt wird. Siehe Michael Burr's Antwort für die vollständigen Details.
Es gibt einen Unterschied, aber einen subtilen. Sehen Sie es so: struct Foo
führt einen neuen Typ ein. Die zweite erzeugt einen Alias namens Foo (und nicht einen neuen Typ) für einen unbenannten struct
-Typ.
7.1.3 Der typedef-Spezifizierer
1 [...]
Ein mit dem typedef specifier deklarierter Name wird zu einem typedef-name. Innerhalb des Geltungsbereichs seiner Deklaration ist ein typedef-name ist im Rahmen seiner Deklaration syntaktisch äquivalent zu einem Schlüsselwort und benennt den mit dem Bezeichner assoziierten Typ in der in Klausel 8 beschriebenen Weise. Ein typedef-name ist also ein Synonym für einen anderen Typ. Ein typedef-name führt keinen neuen Typ ein, wie es eine Klassendeklaration (9.1) oder eine enum-Deklaration tut.
8 Wenn die typedef-Deklaration eine unbenannte Klasse (oder enum) definiert, wird der erste typedef-Name, der durch die Deklaration deklariert wird, um diesen Klassentyp (oder Enum-Typ) zu bezeichnen, wird der Klassentyp (oder Enum-Typ) nur für Verknüpfungszwecke nur für Verknüpfungszwecke verwendet (3.5). [Beispiel:
typedef struct { } *ps, S; // S is the class name for linkage purposes
Ein typedef wird also immer als Platzhalter/Synonym für einen anderen Typ verwendet.