Frage

In C++ gibt es da einen Unterschied zwischen:

struct Foo { ... };

und

typedef struct { ... } Foo;
War es hilfreich?

Lösung

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

Die Sprache C-Standard ( C89 §3.1.2.3 , C99 § 6.2.3 und C11 § 6.2.3 ) Mandate eigenen Namensraum für verschiedene Kategorien von Identifikatoren, einschließlich < em> Tag-Kennungen (für struct / union / enum) und gewöhnliche Bezeichner (für typedef und andere Identifizierungsmerkmale).

Wenn Sie gerade gesagt:

struct Foo { ... };
Foo x;

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

würden Sie müssen erklären ihn als:

struct Foo x;

Jedes Mal, wenn Sie auf eine Foo beziehen möchten, dann würden Sie immer es müssen nennen struct Foo. Das nervt schnell, so können Sie eine typedef hinzufügen:

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

Jetzt struct Foo (im Tag-Namespace) und einfach nur Foo (im gewöhnlichen Bezeichner Namespace), die beide auf die gleiche Sache beziehen, und Sie können frei Objekte vom Typ Foo ohne struct Schlüsselwort deklarieren.


Das Konstrukt:

typedef struct Foo { ... } Foo;

ist nur eine Abkürzung für die Erklärung und typedef.


Schließlich

typedef struct { ... } Foo;

erklärt eine anonyme Struktur und schafft eine typedef dafür. So mit diesem Konstrukt, ist es nicht einen Namen im Tag-Namespace hat, nur einen Name in dem typedef-Namespace. Das bedeutet, es kann auch nicht die Zukunft gerichteten Begriffen erklärt. Wenn Sie eine Vorwärtsdeklaration machen wollen, haben Sie es in der Tag-Namespace einen Namen geben .


In C ++, alle struct / union / enum / class Erklärungen handeln, wie sie implizit typedef'ed werden, solange der Name nicht durch eine andere Erklärung mit dem gleichen Namen verbirgt. Siehe Michael Burr Antwort für die vollständigen Details .

Andere Tipps

dieser DDJ Artikel , Dan Saks, erklärt ein kleiner Bereich, in dem Fehler einschleichen können durch wenn Sie nicht typedef Ihre structs (und Klassen!):

  

Wenn Sie wollen, können Sie das C ++ vorstellen   erzeugt ein typedef für jeden Tag   Namen wie

typedef class string string;
     

Leider ist dies nicht ganz   genau. Ich wünschte, es wäre so einfach,   aber es ist nicht. C ++ können solche erzeugen   typedefs für structs, Gewerkschaften oder Aufzählungen   ohne Einführung von Inkompatibilitäten   mit C.

     

Beispiel: Angenommen, ein C-Programm   erklärt sowohl eine Funktion und eine Struktur   genannt Status:

int status(); struct status;
     

Auch hier kann diese schlechte Praxis sein, aber   es ist C. In diesem Programm-Status (durch   selbst) bezieht sich auf die Funktion; struct   Status bezieht sich auf die Art.

     

Wenn C ++ automatisch haben generieren   typedefs für Tags, dann, wenn Sie   Dieses Programm als C ++ kompiliert wird, die   Compiler erzeugen würde:

typedef struct status status;
     

Leider ist dieser Typ Name würde   in Konflikt mit dem Funktionsnamen und   würde das Programm nicht kompilieren. das ist   warum C ++ kann nicht einfach eine generieren   typedef für jeden Tag.

     

In C ++ Tags wirken wie typedef   Namen, mit der Ausnahme, dass ein Programm   erklären, ein Objekt, eine Funktion oder   enumerator mit dem gleichen Namen und der   gleicher Umfang wie ein Tag. In diesem Fall wird die   Aufgabe, Funktion oder Enumerator name   versteckt den Tag-Namen. Das Programm kann   beziehen sich auf den Tag-Namen nur mit   das Schlüsselwort Klasse, Struktur, Vereinigung oder   enum (je nachdem) vor dem   Verlinke den Namen. Ein Name, Typ, bestehend aus   einer dieser gefolgt von einem keywords   Tag ist ein erarbeitet-Typ-Spezifizierer.   Zum Beispiel struct Status und Enum   Monat erarbeitet Typ-Spezifizierer.

     

So wird ein C-Programm, das beide enthält:

int status(); struct status;
     

verhält sich genauso, wenn sie als C ++ kompiliert.   Der Name Status bezieht sich allein auf die   Funktion. Das Programm kann auf das beziehen   Typ nur durch die Verwendung von   erarbeitet-type-specifier struct   Status.

     

Wie lässt diese Fehler zu kriechen   in Programme? Betrachten Sie das Programm in    Listing 1 . In diesem Programm wird ein   class foo mit einem Default-Konstruktor,   und ein Umwandlungs Operator,   wandelt ein foo Objekt char * const.   Der Ausdruck

p = foo();
     

in Haupt sollte ein foo-Objekt erstellen   und wenden Sie den Konvertierungsoperator. Das   nachfolgende Ausgabeanweisung

cout << p << '\n';
     

sollte class foo anzuzeigen, aber es   nicht. Es zeigt Funktion foo.

     

Dieses überraschende Ergebnis tritt auf, weil   Das Programm beinhaltet Header lib.h   in Listing 2 gezeigt. Dieser Header   auch foo definiert eine Funktion mit dem Namen. Das   Funktionsname foo versteckt den Klassennamen   foo, so dass der in Bezug auf foo Haupt   bezieht sich auf die Funktion, nicht die Klasse.   Haupt kann nur auf die Klasse verweisen, indem   Verwendung eines ausgearbeiteten-Typ-Spezifizierer, wie   in

p = class foo();
     

Die Möglichkeit, solche Verwechslungen zu vermeiden   Während des Programms ist das hinzufügen   folgende typedef für die Klassennamen   foo:

typedef class foo foo;
     

unmittelbar vor oder nach der Klasse   Definition. Diese typedef bewirkt ein   Konflikt zwischen dem Typnamen foo und   der Name der Funktion foo (von der   Bibliothek), der eine triggert   Fehler bei der Kompilierung.

     

Ich kenne niemanden, der tatsächlich schreibt   diese typedefs als selbstverständlich.   Es erfordert eine Menge Disziplin. Schon seit   die Häufigkeit von Fehlern, wie beispielsweise die   ein in 1 Listing ist wahrscheinlich ziemlich   klein, viele nie in Konflikt geraten laufen von   dieses Problem. Aber wenn ein Fehler in Ihrem   Software könnte zu Verletzungen führen,   dann sollten Sie die typedefs schreiben nein   Ganz gleich, wie unlikely den Fehler.

     

Ich kann mich nicht vorstellen, warum jemand würde jemals   will einen Klassennamen mit einem verstecken   Funktions- oder Objektnamens in der gleichen   Umfang wie die Klasse. Die Ausblendregeln   in C waren ein Fehler, und sie sollten   nicht auf Klassen erweitert wurde   C ++. Tatsächlich können Sie die richtigen   Fehler, aber es erfordert zusätzliche   Programmierung Disziplin und Mühe, die   sollte nicht notwendig sein.

Ein weiterer wichtiger Unterschied: typedefs kann nicht vorwärts deklariert werden. Also für die typedef Option müssen Sie die Datei #include die typedef enthält, alles was bedeutet, dass Ihr #include .hs enthält auch die Datei, ob es sie direkt braucht oder nicht, und so weiter. Es kann auf jeden Fall Ihre Bauzeiten auf größere Projekte auswirken.

Ohne die typedef, in einigen Fällen können Sie nur eine Vorwärtserklärung struct Foo; an der Spitze Ihrer .h Datei hinzufügen, und #include nur die Struktur Definition in Ihrer .cpp Datei.

Es ist ein Unterschied, aber subtil.Betrachten Sie es so: struct Foo führt einen neuen Typ.Die zweite erzeugt einen alias namens Foo (und nicht ein neuer Typ) für eine Unbenannte struct Typ.

7.1.3 Dem typedef Spezifizierer

1 [...]

Einen Namen deklariert mit dem typedef Spezifizierer wird ein typedef-Namen.Im Rahmen seiner Erklärung, eine typedef-name ist syntaktisch äquivalent zu einem Schlüsselwort und den Namen der im Zusammenhang mit dem Bezeichner in die Art und Weise, beschrieben in Klausel 8.Ein typedef-name ist also ein synonym für einen anderen Typ.Ein typedef-name nicht die Einführung einer neuen Art die Art und Weise der Deklaration einer Klasse (9.1) oder enum-Deklaration hat.

8 Wenn der typedef-Deklaration definiert eine Unbenannte Klasse (oder enum), die erste typedef-Namen deklariert die Deklaration zu dieser Klasse geben (oder enum-Typ) verwendet, um anzugeben, die Klasse geben (oder enum-Typ) für die Verknüpfung Zwecken (3.5).[ Beispiel:

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

So, typedef immer als Platzhalter/synonym für einen anderen Typ.

Sie können nicht mit dem typedef struct verwenden Forward-Deklaration.

Die Struktur selbst ist ein anonymer Typ, so dass Sie nicht einen tatsächlichen Namen declare weiterleiten müssen.

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

Eine Vorwärtsdeklaration wie diese nicht funktionieren:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

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

Struct ist ein Datentyp zu erstellen. Der typedef ist einen Spitznamen für einen Datentyp eingestellt werden.

Ein wichtiger Unterschied zwischen einem 'typedef struct' und einer 'Struktur' in C ++ ist, dass Inline-Mitglied Initialisierung in 'typedef structs' wird nicht funktionieren.

// 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; };

Es gibt keinen Unterschied in C ++, aber ich glaube an C erlauben würden Sie Instanzen der struct Foo zu erklären, ohne explizit zu tun:

struct Foo bar;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top