typedef struct vs. Strukturdefinitionen

Ich bin ein Anfänger in C-Programmierung, aber ich frage mich, was ist der Unterschied zwischen der Verwendung von Typedef bei der Definition einer Struktur gegenüber nicht mit Typedef. Es scheint mir, als gäbe es keinen Unterschied, sie erreichen dasselbe.

struct myStruct{ int one; int two; }; 

gegen

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

Solutions Collecting From Web of "typedef struct vs. Strukturdefinitionen"

Das allgemeine Idiom verwendet beide:

 typedef struct X { int x; } X; 

Sie sind unterschiedliche Definitionen. Um die Diskussion klarer zu machen, werde ich den Satz aufteilen:

 struct S { int x; }; typedef struct SS; 

In der ersten Zeile definieren Sie den Bezeichner S innerhalb des Namensraums der Struktur (nicht in der C ++ – Richtung). Sie können es verwenden und Variablen oder functionsargumente des neu definierten Typs definieren, indem Sie den Typ des Arguments als struct S :

 void f( struct S argument ); // struct is required here 

Die zweite Zeile fügt einen Typ-Alias S im globalen Namensraum hinzu und erlaubt Ihnen so einfach zu schreiben:

 void f( S argument ); // struct keyword no longer needed 

Beachten Sie, dass die Definition von S sowohl in den Strukturen als auch in den globalen Leerzeichen kein Fehler ist, da beide Bezeichnernamespaces unterschiedlich sind, da es nicht den gleichen Bezeichner neu definiert, sondern stattdessen einen anderen Bezeichner an einem anderen Ort erstellt.

Um den Unterschied deutlicher zu machen:

 typedef struct S { int x; } T; void S() { } // correct //void T() {} // error: symbol T already defined as an alias to 'struct S' 

Sie können eine function mit dem gleichen Namen der Struktur definieren, da die Bezeichner in verschiedenen Leerzeichen typedef Sie können jedoch keine function mit dem gleichen Namen wie ein typedef da diese Bezeichner kollidieren.

In C ++ ist es etwas anders, da die Regeln zum Lokalisieren eines Symbols sich subtil geändert haben. C ++ behält immer noch die zwei verschiedenen Bezeichnerbereiche bei, aber im Gegensatz zu C müssen Sie, wenn Sie nur das Symbol innerhalb des classnbezeichnerbereichs definieren, das Schlüsselwort struct / class nicht angeben:

  // C++ struct S { int x; }; // S defined as a class void f( S a ); // correct: struct is optional 

Was ändert sich, sind die Suchregeln, nicht wo die Bezeichner definiert sind. Der Compiler durchsucht die globale Bezeichner-Tabelle und nachdem S nicht gefunden wurde, wird er innerhalb der classnbezeichner nach S suchen.

Der vorgestellte Code verhält sich auf die gleiche Weise:

 typedef struct S { int x; } T; void S() {} // correct [*] //void T() {} // error: symbol T already defined as an alias to 'struct S' 

Nach der Definition der S function in der zweiten Zeile kann die Struktur S nicht automatisch vom Compiler aufgetriggers werden. Um ein Objekt zu erstellen oder ein Argument dieses Typs zu definieren, müssen Sie auf das Schlüsselwort struct zurückgreifen:

 // previous code here... int main() { S(); struct S s; } 

struct und typedef sind zwei sehr unterschiedliche Dinge.

Das Schlüsselwort struct wird verwendet, um einen Strukturtyp zu definieren oder sich darauf zu beziehen. Zum Beispiel:

 struct foo { int n; }; 

erstellt einen neuen Typ namens struct foo . Der Name foo ist ein Tag ; Es ist nur dann sinnvoll, wenn dem Schlüsselwort struct unmittelbar vorangestellt wird, da sich Tags und andere Bezeichner in unterschiedlichen Namensräumen befinden . (Dies ist ähnlich, aber viel stärker eingeschränkt als das C ++ Konzept von namespace .)

Ein typedef definiert trotz des Namens keinen neuen Typ; Es erstellt lediglich einen neuen Namen für einen vorhandenen Typ. Zum Beispiel gegeben:

 typedef int my_int; 

my_int ist ein neuer Name für int ; my_int und int sind genau gleich. Entsprechend können Sie bei der obigen struct schreiben:

 typedef struct foo foo; 

Der Typ hat bereits einen Namen, struct foo . Die typedef Deklaration gibt dem gleichen Typ einen neuen Namen foo .

Mit der Syntax können Sie eine struct und eine typedef zu einer einzigen Deklaration kombinieren:

 typedef struct bar { int n; } bar; 

Dies ist ein allgemeines Idiom. Nun können Sie diesen Strukturtyp entweder als struct bar oder nur als bar .

Beachten Sie, dass der typedef-Name erst am Ende der Deklaration sichtbar wird. Wenn die Struktur einen pointers auf sich selbst enthält, verwenden Sie die struct , um auf sie zu verweisen:

 typedef struct node { int data; struct node *next; /* can't use just "node *next" here */ } node; 

Einige Programmierer verwenden unterschiedliche Bezeichner für das struct-Tag und den typedef-Namen. Meiner Meinung nach gibt es keinen guten Grund dafür; Die Verwendung desselben Namens ist vollkommen legal und verdeutlicht, dass es sich um denselben Typ handelt. Wenn Sie verschiedene Bezeichner verwenden müssen, verwenden Sie mindestens eine konsistente Konvention:

 typedef struct node_s { /* ... */ } node; 

(Persönlich bevorzuge ich es, typedef wegzulassen und auf den Typ als struct bar verweisen. Der typedef speichert ein wenig Typisierung, aber es versteckt die Tatsache, dass es ein Strukturtyp ist. Wenn der Typ undurchsichtig sein soll, kann das ein guter sein Wenn Client-Code sich namentlich auf das Mitglied n bezieht, dann ist es nicht undurchsichtig, es ist sichtbar eine Struktur, und meiner Meinung nach macht es Sinn, es als Struktur zu bezeichnen, aber viele schlaue Programmierer widersprechen mir in diesem Punkt: Seien Sie darauf vorbereitet, Code zu lesen und zu verstehen, der in beide Richtungen geschrieben ist.)

(C ++ hat andere Regeln. Bei einer Deklaration von struct blah , können Sie den Typ einfach als blah , auch ohne typedef. Mit typedef könnte Ihr C-Code etwas mehr C ++ – wie – wenn Sie das für gut halten Ding.)

Ein weiterer nicht aufgeführter Unterschied besteht darin, dass Sie der Struktur einen Namen geben können (dh struct myStruct), um auch Vorwärtsdeklarationen der Struktur bereitstellen zu können. In einer anderen Datei könnten Sie also schreiben:

 struct myStruct; void doit(struct myStruct *ptr); 

ohne Zugang zu der Definition zu haben. Ich empfehle Ihnen, Ihre zwei Beispiele zu kombinieren:

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

Dies gibt Ihnen die Bequemlichkeit des knapperen typedef-Namens, aber Sie können trotzdem den vollständigen Namen der Struktur verwenden, wenn Sie es benötigen.

In C (nicht C ++) müssen Sie Strukturvariablen deklarieren wie:

 struct myStruct myVariable; 

Um myStruct myVariable; Stattdessen können typedef die Struktur typedef :

 typedef struct myStruct someStruct; someStruct myVariable; 

Sie können struct definition und typedef es in einer einzigen statement kombinieren, die eine anonyme struct deklariert und typedef es deklariert.

 typedef struct { ... } myStruct; 

Wenn Sie struct ohne typedef , müssen Sie immer schreiben

 struct mystruct myvar; 

Es ist illegal zu schreiben

 mystruct myvar; 

Wenn Sie den typedef verwenden, brauchen Sie das struct nicht mehr.

In C sind die Schlüsselwörter des Typspezifizierers für Strukturen, Vereinigungen und Aufzählungen obligatorisch, dh Sie müssen dem Namen des Typs (dessen Tag ) immer den Namen struct , union oder enum wenn Sie auf den Typ verweisen.

Sie können die Schlüsselwörter loswerden, indem Sie typedef , eine Form der Informationsverbergung, da der tatsächliche Typ eines Objekts bei der Deklaration nicht mehr sichtbar ist.

Es wird daher empfohlen (siehe z. B. den Linux-coreel-Coding-Styleguide , Kapitel 5), dies nur dann zu tun, wenn Sie diese Informationen wirklich ausblenden und nicht nur ein paar Tastenanschläge speichern möchten .

Ein Beispiel für die Verwendung eines typedef wäre ein undurchsichtiger Typ, der nur mit entsprechenden Accessor-functionen / Makros verwendet wird.

Der Unterschied kommt, wenn Sie die struct .

Der erste Weg, den Sie machen müssen:

 struct myStruct aName; 

Die zweite Möglichkeit ermöglicht es, das Schlüsselwort struct zu entfernen.

 myStruct aName; 

Sie können die forward-Deklaration nicht mit der typedef struct .

Die struct selbst ist ein anonymer Typ, Sie haben also keinen Namen zum Weiterleiten der Deklaration.

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

Eine solche Vorwärtsdeklaration wird nicht funktionieren:

 struct myStruct; //forward declaration fails void blah(myStruct* pStruct); //error C2371: 'myStruct' : redefinition; different basic types 

Der typedef , wie bei anderen Konstrukten, verwendet, um einem Datentyp einen neuen Namen zu geben. In diesem Fall wird es meistens gemacht, um den Code sauberer zu machen:

 struct myStruct blah; 

gegen

 myStruct blah; 

Der folgende Code erstellt eine anonyme Struktur mit dem Alias myStruct :

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

Sie können nicht ohne den Alias ​​darauf verweisen, da Sie keinen Bezeichner für die Struktur angeben.

Ich sehe eine Klärung in dieser Reihenfolge. C und C ++ definieren Typen nicht anders. C ++ war ursprünglich nichts anderes als ein zusätzlicher Satz von Includes auf C.

Das Problem, das heute praktisch alle C / C ++ – Entwickler haben, ist: a) Universitäten lehren nicht mehr die Grundlagen und b) Menschen verstehen den Unterschied zwischen einer Definition und einer Deklaration nicht.

Der einzige Grund, warum solche Deklarationen und Definitionen existieren, besteht darin, dass der Linker Adressoffsets für die Felder in der Struktur berechnen kann. Deshalb kommen die meisten Leute mit falsch geschriebenem Code davon, weil der Compiler die Adressierung bestimmen kann. Das Problem tritt auf, wenn jemand versucht, etwas voranzutreiben, wie eine Warteschlange oder eine verknüpfte Liste, oder eine O / S-Struktur unterstützt.

Eine Deklaration beginnt mit ‘struct’, eine Definition beginnt mit ‘typedef’.

Außerdem hat eine Struktur eine Vorwärtsdeklaration und ein definiertes Label. Die meisten Leute wissen das nicht und verwenden das Forward-Deklarations-Label als Definitions-Label.

Falsch:

 struct myStruct { int field_1; ... }; 

Sie haben gerade die forward-Deklaration verwendet, um die Struktur zu beschriften – also ist sich der Compiler dessen bewusst – aber es ist kein wirklich definierter Typ. Der Compiler kann die Adressierung berechnen – aber aus Gründen, die ich kurz zeigen werde, ist dies nicht beabsichtigt.

Leute, die diese Form der Deklaration benutzen, müssen ‘struct’ praktisch in jeden Bezug darauf setzen – weil es kein offizieller neuer Typ ist.

Stattdessen sollte jede Struktur, die sich nicht selbst referenziert, nur auf diese Weise deklariert und definiert werden:

 typedef struct { field_1; ... }myStruct; 

Nun ist es ein tatsächlicher Typ, und wenn Sie ihn verwenden, können Sie ihn als ‘myStruct’ verwenden, ohne ihn mit dem Wort ‘struct’ voranstellen zu müssen.

Wenn Sie eine pointersvariable für diese Struktur wünschen, fügen Sie eine sekundäre Beschriftung hinzu:

 typedef struct { field_1; ... }myStruct,*myStructP; 

Jetzt haben Sie eine pointersvariable auf diese Struktur, die für sie benutzerdefiniert ist.

VORAUSDEKLARATION–

Nun, hier ist das ausgefallene Zeug, wie die Vorwärtsdeklaration funktioniert. Wenn Sie einen Typ erstellen möchten, der auf sich selbst verweist, wie eine verknüpfte Liste oder ein Warteschlangenelement, müssen Sie eine Vorwärtsdeklaration verwenden. Der Compiler berücksichtigt die definierte Struktur nicht, bis er das Semikolon ganz am Ende erreicht, also wurde er vor diesem Punkt deklariert.

 typedef struct myStructElement { myStructElement* nextSE; field_1; ... }myStruct; 

Nun weiß der Compiler, dass er zwar noch nicht weiß, was der ganze Typ ist, er kann ihn jedoch immer noch mit der Vorwärtsreferenz referenzieren.

Bitte deklarieren und tippen Sie Ihre Strukturen korrekt ein. Es gibt einen Grund.

Bei letzterem Beispiel wird das Schlüsselwort struct bei der Verwendung der Struktur weggelassen. So können Sie überall in Ihrem Code schreiben:

 myStruct a; 

Anstatt von

 struct myStruct a; 

Dies spart ein wenig Tipparbeit und könnte besser lesbar sein, aber das ist Geschmackssache