Unterschied zwischen ‘struct’ und ‘typedef struct’ in C++?

Lesezeit: 12 Minuten

Unterschied zwischen struct und typedef struct in C
credell

Im C++gibt es einen Unterschied zwischen:

struct Foo { ... };

und:

typedef struct { ... } Foo;

  • Verwandte Frage und Antwort: Unterschied zwischen using und typedef in C++11

    – Jost

    9. März 2016 um 8:51 Uhr


  • Siehe auch die verwandte Frage zu C

    – Raedwald

    17. Oktober 2016 um 15:46 Uhr

1647253813 25 Unterschied zwischen struct und typedef struct in C
Adam Rosenfeld

In C++ gibt es nur einen feinen Unterschied. Es ist ein Überbleibsel von C, in dem es einen Unterschied macht.

Der C-Sprachstandard (C89 §3.1.2.3, C99 §6.2.3und C11 §6.2.3) schreibt separate Namensräume für verschiedene Kategorien von Bezeichnern vor, einschließlich Tag-Identifikatoren (zum struct/union/enum) und gewöhnliche Kennungen (zum typedef und andere Identifikatoren).

Wenn du gerade gesagt hast:

struct Foo { ... };
Foo x;

Sie würden einen Compiler-Fehler erhalten, weil Foo ist nur im Tag-Namensraum definiert.

Sie müssten es wie folgt deklarieren:

struct Foo x;

Jedes Mal, wenn Sie sich auf a beziehen möchten Foomüsstest du es immer a nennen struct Foo. Das wird schnell lästig, also kannst du a hinzufügen typedef:

struct Foo { ... };
typedef struct Foo Foo;

Jetzt struct Foo (im Tag-Namensraum) und einfach nur Foo (im gewöhnlichen Bezeichner-Namensraum) beziehen sich beide auf dasselbe, und Sie können Objekte des Typs frei deklarieren Foo ohne das struct Stichwort.


Das Konstrukt:

typedef struct Foo { ... } Foo;

ist nur eine Abkürzung für die Deklaration und typedef.


Endlich,

typedef struct { ... } Foo;

deklariert eine anonyme Struktur und erstellt eine typedef dafür. Bei diesem Konstrukt hat es also keinen Namen im Tag-Namensraum, sondern nur einen Namen im Typedef-Namensraum. Dies bedeutet, dass es auch nicht vorwärts deklariert werden kann. Wenn Sie eine Vorwärtsdeklaration vornehmen möchten, müssen Sie ihr einen Namen im Namensraum des Tags geben.


In C++ alle struct/union/enum/class Deklarationen verhalten sich so, als wären sie implizit typedef‘ed, solange der Name nicht durch eine andere gleichnamige Deklaration verdeckt wird. Die vollständigen Details finden Sie in der Antwort von Michael Burr.

  • Während das, was Sie sagen, wahr ist, AFAIK, die Aussage ‘typedef struct { … } Foo;’ erstellt einen Alias ​​für eine unbenannte Struktur.

    – dirkgent

    4. März 2009 um 20:51 Uhr

  • Guter Fang, es gibt einen feinen Unterschied zwischen “typedef struct Foo { … } Foo;” und “typedef struct { … } Foo;”.

    – Adam Rosenfield

    4. März 2009 um 21:00 Uhr

  • In C teilen sich die Struct-Tags, Union-Tags und Aufzählungs-Tags einen Namensraum, anstatt (struct und union) wie oben behauptet zwei zu verwenden; der Namespace, auf den für Typedef-Namen verwiesen wird, ist tatsächlich separat. Das bedeutet, dass Sie nicht beides haben können ‘union x { … };’ und ‘struct x { … };’ in einem einzigen Bereich.

    – Jonathan Leffler

    11. Juni 2009 um 4:28 Uhr

  • Abgesehen von der not-quite-typedef-Sache besteht ein weiterer Unterschied zwischen den beiden Codeteilen in der Frage darin, dass Foo im ersten Beispiel einen Konstruktor definieren kann, im zweiten jedoch nicht (da anonyme Klassen keine Konstruktoren oder Destruktoren definieren können). .

    – Steve Jessop

    22. November 2009 um 2:45 Uhr

  • @Lazer: Da sind subtile Unterschiede, aber Adam meint (wie er weiter sagt), dass Sie ‘Type var’ verwenden können, um Variablen ohne Typedef zu deklarieren.

    – Fred Nurk

    7. Februar 2011 um 20:49 Uhr

1647253814 814 Unterschied zwischen struct und typedef struct in C
Michael Burr

Im diesen DDJ-ArtikelDan Saks erklärt einen kleinen Bereich, in dem sich Fehler einschleichen können, wenn Sie Ihre Strukturen (und Klassen!) nicht typdefinieren:

Wenn Sie möchten, können Sie sich vorstellen, dass C++ für jeden Tag-Namen eine Typedef generiert, z

typedef class string string;

Leider ist dies nicht ganz korrekt. Ich wünschte, es wäre so einfach, aber das ist es nicht. C++ kann solche Typedefs nicht für Strukturen, Vereinigungen oder Aufzählungen generieren, ohne Inkompatibilitäten mit C einzuführen.

Angenommen, ein C-Programm deklariert sowohl eine Funktion als auch eine Struktur namens status:

int status(); struct status;

Auch dies mag eine schlechte Praxis sein, aber es ist C. In diesem Programm bezieht sich der Status (an sich) auf die Funktion; struct status bezieht sich auf den Typ.

Wenn C++ automatisch Typedefs für Tags generiert hätte, würde der Compiler beim Kompilieren dieses Programms als C++ Folgendes generieren:

typedef struct status status;

Leider würde dieser Typname mit dem Funktionsnamen in Konflikt geraten, und das Programm würde nicht kompiliert. Aus diesem Grund kann C++ nicht einfach eine Typedef für jedes Tag generieren.

In C++ verhalten sich Tags genauso wie Typedef-Namen, außer dass ein Programm ein Objekt, eine Funktion oder einen Enumerator mit demselben Namen und demselben Gültigkeitsbereich wie ein Tag deklarieren kann. In diesem Fall verbirgt der Name des Objekts, der Funktion oder des Enumerators den Tag-Namen. Das Programm kann nur auf den Tag-Namen verweisen, indem es das Schlüsselwort class, struct, union oder enum (je nach Bedarf) vor dem Tag-Namen verwendet. Ein Typname, der aus einem dieser Schlüsselwörter gefolgt von einem Tag besteht, ist ein ausgearbeiteter Typbezeichner. Beispielsweise sind struct status und enum month ausgearbeitete Typspezifizierer.

Also ein C-Programm, das beides enthält:

int status(); struct status;

verhält sich genauso, wenn es als C++ kompiliert wird. Allein der Namensstatus bezieht sich auf die Funktion. Das Programm kann sich nur auf den Typ beziehen, indem es den Elaborated-Type-Specifier-Strukturstatus verwendet.

Wie also können sich Fehler in Programme einschleichen? Betrachten Sie das Programm in
Auflistung 1. Dieses Programm definiert eine Klasse foo mit einem Standardkonstruktor und einem Konvertierungsoperator, der ein foo-Objekt in char const * konvertiert. Der Ausdruck

p = foo();

sollte hauptsächlich ein foo-Objekt konstruieren und den Konvertierungsoperator anwenden. Die nachfolgende Ausgabeanweisung

cout << p << '\n';

sollte class foo anzeigen, tut es aber nicht. Es zeigt die Funktion foo an.

Dieses überraschende Ergebnis tritt auf, weil das Programm den in gezeigten Header lib.h enthält Auflistung 2. Dieser Header definiert eine Funktion, die auch foo heißt. Der Funktionsname foo verbirgt den Klassennamen foo, daher bezieht sich der Verweis auf foo in main auf die Funktion, nicht auf die Klasse. main kann sich nur auf die Klasse beziehen, indem ein ausgearbeiteter Typbezeichner verwendet wird, wie in

p = class foo();

Um eine solche Verwirrung im gesamten Programm zu vermeiden, fügen Sie die folgende Typedef für den Klassennamen foo hinzu:

typedef class foo foo;

unmittelbar vor oder nach der Klassendefinition. Diese Typedef verursacht einen Konflikt zwischen dem Typnamen foo und dem Funktionsnamen foo (aus der Bibliothek), der einen Kompilierzeitfehler auslöst.

Ich kenne niemanden, der diese Typedefs tatsächlich selbstverständlich schreibt. Es erfordert viel Disziplin. Da das Auftreten von Fehlern wie dem in Auflistung 1 wahrscheinlich ziemlich klein ist, werden Sie viele nie mit diesem Problem in Konflikt geraten. Aber wenn ein Fehler in Ihrer Software zu Körperverletzungen führen könnte, dann sollten Sie die Typedefs schreiben, egal wie unwahrscheinlich der Fehler ist.

Ich kann mir nicht vorstellen, warum jemand jemals einen Klassennamen mit einem Funktions- oder Objektnamen im selben Bereich wie die Klasse verbergen möchte. Die Versteckregeln in C waren ein Fehler, und sie hätten nicht auf Klassen in C++ ausgedehnt werden sollen. Sie können den Fehler zwar korrigieren, aber es erfordert zusätzliche Programmierdisziplin und -aufwand, die nicht notwendig sein sollten.

  • Falls Sie “class foo()” versuchen und es fehlschlägt: In ISO C++ ist “class foo()” ein illegales Konstrukt (der Artikel wurde ’97 geschrieben, anscheinend vor der Standardisierung). Sie können “typedef class foo foo;” in main, dann kannst du “foo();” sagen (denn dann ist der Typedef-Name lexikalisch näher als der Name der Funktion). Syntaktisch muss T in T() ein einfacher Typbezeichner sein. Ausgearbeitete Typbezeichner sind nicht erlaubt. Trotzdem ist dies natürlich eine gute Antwort.

    – Johannes Schaub – litb

    5. Juli 2009 um 21:36 Uhr

  • Listing 1 und Listing 2 Links sind kaputt. Guck mal.

    – Prasun Saurav

    13. Oktober 2010 um 17:05 Uhr

  • Wenn Sie unterschiedliche Namenskonventionen für Klassen und Funktionen verwenden, vermeiden Sie auch den Namenskonflikt, ohne zusätzliche Typedefs hinzufügen zu müssen.

    – zstewart

    9. Mai 2017 um 16:34 Uhr

Unterschied zwischen struct und typedef struct in C
Jo

Noch ein wichtiger Unterschied: typedefs können nicht vorwärts deklariert werden. Also für die typedef Option müssen Sie #include die Datei, die die enthält typedefalso alles das #includeist dein .h enthält diese Datei auch, unabhängig davon, ob sie direkt benötigt wird oder nicht, und so weiter. Es kann sich definitiv auf Ihre Bauzeiten bei größeren Projekten auswirken.

Ohne das typedefin einigen Fällen können Sie einfach eine Vorwärtsdeklaration von hinzufügen struct Foo; an der Spitze Ihrer .h Datei, und nur #include die Strukturdefinition in Ihrer .cpp Datei.

  • Warum wirkt sich das Verfügbarmachen der Definition von struct auf die Buildzeit aus? Führt der Compiler zusätzliche Überprüfungen durch, auch wenn dies nicht erforderlich ist (angesichts der typedef-Option, damit der Compiler die Definition kennt), wenn er etwas wie sieht Foo* nextFoo;?

    – Reich

    12. März 2014 um 17:21 Uhr


  • Es ist nicht wirklich eine zusätzliche Überprüfung, es ist nur mehr Code, mit dem der Compiler umgehen muss. Für jede cpp-Datei, die irgendwo in ihrer Include-Kette auf diese Typedef trifft, wird die Typedef kompiliert. In größeren Projekten könnte die .h-Datei, die die Typedef enthält, leicht hunderte Male kompiliert werden, obwohl vorkompilierte Header sehr hilfreich sind. Wenn Sie mit der Verwendung einer Vorwärtsdeklaration davonkommen, ist es einfacher, die Einbeziehung der .h-Datei, die die vollständige Strukturspezifikation enthält, nur auf den Code zu beschränken, der wirklich wichtig ist, und daher wird die entsprechende Include-Datei seltener kompiliert.

    – Jo

    12. März 2014 um 20:02 Uhr

  • Bitte @ den vorherigen Kommentator (außer dem Eigentümer des Beitrags). Fast hätte ich deine Antwort verpasst. Aber danke für die Info.

    – Reich

    13. März 2014 um 16:43 Uhr

  • Dies gilt nicht mehr in C11, wo Sie dieselbe Struktur mit demselben Namen mehrmals eingeben können.

    – Michaelmeyer

    13. September 2015 um 16:13 Uhr

  • @Joe: Ein weiteres Problem war in der Vergangenheit das bei der Verwendung struct tagName Syntax kann eine zwei Header-Dateien haben, die jeweils eine Funktion enthalten, die einen Zeiger auf eine in der anderen definierte Struktur akzeptiert, während eine Definition jeder Struktur zwischen ihnen vorhanden ist.

    – Superkatze

    19. Juni 2020 um 21:50 Uhr

1647253815 63 Unterschied zwischen struct und typedef struct in C
dirkly

Dort ist ein Unterschied, aber subtil. Betrachten Sie es so: struct Foo stellt einen neuen Typ vor. Der zweite erstellt einen Alias ​​namens Foo (und keinen neuen Typ) für einen unbenannten struct Art.

7.1.3 Der typedef-Bezeichner

1 […]

Ein mit dem typedef-Bezeichner deklarierter Name wird zu einem typedef-Namen. Ein Typedef-Name ist im Rahmen seiner Deklaration syntaktisch äquivalent zu einem Schlüsselwort und benennt den Typ, der dem Bezeichner zugeordnet ist, wie in Abschnitt 8 beschrieben. 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 Aufzählungsdeklaration tut.

8 Wenn die Typedef-Deklaration eine unbenannte Klasse (oder Aufzählung) definiert, wird der erste Typedef-Name, der von der Deklaration als dieser Klassentyp (oder Aufzählungstyp) deklariert wird, verwendet, um den Klassentyp (oder Aufzählungstyp) nur für Verknüpfungszwecke zu bezeichnen ( 3.5). [ Example:

typedef struct { } *ps, S; // S is the class name for linkage purposes

So, a typedef always is used as an placeholder/synonym for another type.

You can’t use forward declaration with the typedef struct.

The struct itself is an anonymous type, so you don’t have an actual name to forward declare.

typedef struct{
    int one;
    int two;
}myStruct;

A forward declaration like this wont work:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

  • I don’t get the second error for the function prototype. Why does it say “redefinition; different basic types”? the compiler does not need to know what myStruct’s definition looks like, right? No matter taken from with piece of code (the typedef one, or the forward declaration one), myStruct denotes a struct type, right?

    – Rich

    Mar 12, 2014 at 17:30


  • @Rich It’s complaining that there is a conflict of names. There’s a forward declaration saying “look for a struct called myStruct” and then there’s the typedef which is renaming a nameless structure as “myStruct”.

    – Yochai Timmer

    Mar 13, 2014 at 7:48

  • You mean put both typedef and forward declaration in the same file? I did, and gcc compiled it fine. myStruct is correctly interpreted as the nameless structure. Tag myStruct lives in tag namespace and typedef_ed myStruct lives in the normal namespace where other identifiers like function name, local variable names live in. So there should not be any conflict..I can show you my code if you doubt there is any error in it.

    – Rich

    Mar 13, 2014 at 8:07

  • @Rich GCC gives the same error, text varies a bit: gcc.godbolt.org/…

    – Yochai Timmer

    Mar 13, 2014 at 8:15

  • I think I understand that when you only have a typedef, forward declaration with the typedefed name, does not refer to the unnamed structure. Instead the forward declaration declares an incomplete structure with tag myStruct. Also, without seeing the definition of typedef, the function prototype using the typedefed name is not legal. Thus we have to include the whole typedef whenever we need to use myStruct to denote a type. Correct me if I misunderstood u. Thanks.

    – Rich

    Mar 13, 2014 at 8:23


1647253816 295 Unterschied zwischen struct und typedef struct in C
user2796283

An important difference between a ‘typedef struct’ and a ‘struct’ in C++ is that inline member initialisation in ‘typedef structs’ will not work.

// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;

// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };

  • I don’t get the second error for the function prototype. Why does it say “redefinition; different basic types”? the compiler does not need to know what myStruct’s definition looks like, right? No matter taken from with piece of code (the typedef one, or the forward declaration one), myStruct denotes a struct type, right?

    – Rich

    Mar 12, 2014 at 17:30


  • @Rich It’s complaining that there is a conflict of names. There’s a forward declaration saying “look for a struct called myStruct” and then there’s the typedef which is renaming a nameless structure as “myStruct”.

    – Yochai Timmer

    Mar 13, 2014 at 7:48

  • You mean put both typedef and forward declaration in the same file? I did, and gcc compiled it fine. myStruct is correctly interpreted as the nameless structure. Tag myStruct lives in tag namespace and typedef_ed myStruct lives in the normal namespace where other identifiers like function name, local variable names live in. So there should not be any conflict..I can show you my code if you doubt there is any error in it.

    – Rich

    Mar 13, 2014 at 8:07

  • @Rich GCC gives the same error, text varies a bit: gcc.godbolt.org/…

    – Yochai Timmer

    Mar 13, 2014 at 8:15

  • I think I understand that when you only have a typedef, forward declaration with the typedefed name, does not refer to the unnamed structure. Instead the forward declaration declares an incomplete structure with tag myStruct. Also, without seeing the definition of typedef, the function prototype using the typedefed name is not legal. Thus we have to include the whole typedef whenever we need to use myStruct to denote a type. Correct me if I misunderstood u. Thanks.

    – Rich

    Mar 13, 2014 at 8:23


1647253816 291 Unterschied zwischen struct und typedef struct in C
xian

There is no difference in C++, but I believe in C it would allow you to declare instances of the struct Foo without explicitly doing:

struct Foo bar;

  • Look at @dirkgently’s answer—there is a difference, but it’s subtle.

    – Keith Pinson

    Sep 5, 2012 at 17:51

1001140cookie-checkUnterschied zwischen ‘struct’ und ‘typedef struct’ in C++?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy