it-swarm.com.de

typedef struct vs struct definitions

Ich bin ein Anfänger in der C-Programmierung, aber ich habe mich gefragt, was der Unterschied zwischen der Verwendung von typedef beim Definieren einer Struktur und der Nichtverwendung von typedef ist. Mir scheint, es gibt wirklich keinen Unterschied, sie erreichen das gleiche Ziel.

struct myStruct{
    int one;
    int two;
};

vs.

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

Die gemeinsame Sprache verwendet beide:

typedef struct X { 
    int x; 
} X;

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

struct S { 
    int x; 
};

typedef struct S S;

In der ersten Zeile definieren Sie den Bezeichner S innerhalb des Strukturnamensraums (nicht im Sinne von C++). Sie können es verwenden und Variablen oder Funktionsargumente des neu definierten Typs definieren, indem Sie den Typ des Arguments als struct S definieren:

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

Die zweite Zeile fügt einen Typalias S in den globalen Namensraum ein und ermöglicht es Ihnen, einfach Folgendes zu schreiben:

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

Beachten Sie, dass das Definieren von S sowohl in Strukturen als auch in globalen Räumen kein Fehler ist, da beide Bezeichnernamensräume unterschiedlich sind, da nicht derselbe Bezeichner neu definiert wird, sondern ein anderer Bezeichner an einer anderen Stelle erstellt wird.

Um den Unterschied klarer 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 Funktion mit demselben Namen wie die Struktur definieren, da die Bezeichner an verschiedenen Stellen aufbewahrt werden. Sie können jedoch keine Funktion mit demselben Namen wie typedef definieren, da diese Bezeichner kollidieren.

In C++ ist dies etwas anders, da sich die Regeln zum Suchen eines Symbols geringfügig geändert haben. C++ behält die beiden unterschiedlichen Bezeichnerbereiche bei, aber anders als in C müssen Sie das Schlüsselwort struct/class nicht angeben, wenn Sie das Symbol nur innerhalb des Klassenbezeichnerbereichs definieren:

 // C++
struct S { 
    int x; 
}; // S defined as a class

void f( S a ); // correct: struct is optional

Was ändert, sind die Suchregeln, nicht wo die Bezeichner definiert sind. Der Compiler durchsucht die globale Bezeichnertabelle und sucht nach S innerhalb der Klassenbezeichner, nachdem S nicht gefunden wurde.

Der zuvor dargestellte Code verhält sich wie folgt:

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 Funktion S in der zweiten Zeile kann die Struktur S vom Compiler nicht automatisch aufgelöst 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 auf ihn zu verweisen. Zum Beispiel das:

struct foo {
    int n;
};

erstellt einen neuen Typ mit dem Namen struct foo. Der Name foo ist tag; Dies ist nur dann sinnvoll, wenn unmittelbar vor dem Schlüsselwort struct das Schlüsselwort _ steht, da Tags und andere Bezeichner in unterschiedlichen Namensräumen stehen. (Dies ähnelt dem C++ - Konzept von namespaces, ist jedoch wesentlich eingeschränkter als dieses.)

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

typedef int my_int;

my_int ist ein neuer Name für int; my_int und int sind gena vom selben Typ. Entsprechend können Sie unter Berücksichtigung der obigen struct -Definition schreiben:

typedef struct foo foo;

Der Typ hat bereits einen Namen, struct foo. Die typedef -Deklaration gibt demselben Typ den neuen Namen foo.

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

typedef struct bar {
    int n;
} bar;

Dies ist eine verbreitete Redewendung. Jetzt können Sie auf diesen Strukturtyp entweder als struct bar oder nur als bar verweisen.

Beachten Sie, dass der typedef-Name erst am Ende der Deklaration sichtbar wird. Wenn die Struktur einen Zeiger auf sich selbst enthält, müssen Sie die struct -Version verwenden, um darauf 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 für den typedef-Namen. Meiner Meinung nach gibt es keinen guten Grund dafür; Die Verwendung desselben Namens ist völlig legal und verdeutlicht, dass es sich um denselben Typ handelt. Wenn Sie andere Bezeichner verwenden müssen, verwenden Sie mindestens eine konsistente Konvention:

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

(Ich persönlich ziehe es vor, das typedef wegzulassen und den Typ als struct bar zu bezeichnen. Das typedef erspart ein wenig Tipparbeit, verbirgt aber die Tatsache, dass es sich um einen Strukturtyp handelt. Wenn Sie möchten Wenn der Typ undurchsichtig ist, kann dies eine gute Sache sein. Wenn der Client-Code namentlich auf das Mitglied n verweist, ist er nicht undurchsichtig, sondern eine sichtbare Struktur, und meiner Meinung nach ist dies sinnvoll bezeichne es als eine Struktur. Aber viele kluge Programmierer stimmen mir in diesem Punkt nicht zu. Sei bereit, Code zu lesen und zu verstehen, der so oder so geschrieben wurde.)

(In C++ gelten andere Regeln. Bei einer Deklaration von struct blah können Sie den Typ auch ohne typedef als blah bezeichnen. Durch die Verwendung eines typedef wird Ihr C-Code möglicherweise etwas C++ -ähnlicher. - - Wenn Sie denken, dass das eine gute Sache ist.)

112
Keith Thompson

Ein weiterer Unterschied, auf den nicht hingewiesen wird, besteht darin, dass Sie durch die Benennung der Struktur (d. H. Struct myStruct) auch Forward-Deklarationen der Struktur bereitstellen können. In einer anderen Datei könnten Sie also schreiben:

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

ohne auf die Definition zugreifen zu müssen. Ich empfehle Ihnen, Ihre beiden Beispiele zu kombinieren:

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

Dies gibt Ihnen die Bequemlichkeit des präziseren typedef-Namens, ermöglicht Ihnen aber dennoch, den vollständigen Strukturnamen zu verwenden, wenn Sie dies benötigen.

89

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

struct myStruct myVariable;

Um stattdessen myStruct myVariable; verwenden zu können, können Sie typedef die Struktur:

typedef struct myStruct someStruct;
someStruct myVariable;

Sie können die struct -Definition und die typedef -Definition in einer einzigen Anweisung kombinieren, die eine anonyme struct und eine typedef -Definition deklariert.

typedef struct { ... } myStruct;
55
Mehrdad Afshari

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

struct mystruct myvar;

Es ist illegal zu schreiben

mystruct myvar;

Wenn Sie das typedef verwenden, benötigen Sie das struct -Präfix nicht mehr.

30
RED SOFT ADAIR

In C sind die Schlüsselwörter für die Typspezifikation von Strukturen, Vereinigungen und Aufzählungen obligatorisch, dh Sie müssen dem Namen des Typs (seinem -Tag ) immer struct voranstellen. union oder enum, wenn auf den Typ Bezug genommen wird.

Sie können die Schlüsselwörter entfernen, indem Sie typedef verwenden. Dies ist eine Form von Informationen, die ausgeblendet werden, da der tatsächliche Typ eines Objekts beim Deklarieren nicht mehr sichtbar ist.

Es wird daher empfohlen (siehe zB Linux Kernel Coding Style Guide , Kapitel 5), dies nur zu tun, wenn Sie tatsächlich wollen diese Informationen zu verbergen und nicht nur ein paar Tastenanschläge zu speichern.

Ein Beispiel dafür, wann Sie einen typedef verwenden sollten, wäre ein undurchsichtiger Typ, der immer nur mit entsprechenden Accessor-Funktionen/Makros verwendet wird.

23
Christoph

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

Das struct selbst ist ein anonymer Typ, daher müssen Sie keinen tatsächlichen Namen für die Weiterleitung deklarieren.

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

Eine solche Forward-Deklaration funktioniert nicht:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types
7
Yochai Timmer

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

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

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

6
Wronski

Der Unterschied tritt ein, wenn Sie struct verwenden.

Der erste Weg, den Sie tun müssen:

struct myStruct aName;

Mit der zweiten Methode können Sie das Schlüsselwort struct entfernen.

myStruct aName;
5
jjnguy

Das typedef wird wie bei anderen Konstrukten verwendet, um einem Datentyp einen neuen Namen zu geben. In diesem Fall geschieht dies hauptsächlich, um den Code sauberer zu machen:

struct myStruct blah;

vs.

myStruct blah;
4
RC.

Ich sehe, dass diesbezüglich eine Klarstellung angebracht ist. C und C++ definieren Typen nicht unterschiedlich. C++ war ursprünglich nichts anderes als ein zusätzlicher Satz von Includes über C.

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

Der einzige Grund, warum solche Deklarationen und Definitionen existieren, besteht darin, dass der Linker Adressversätze zu den Feldern in der Struktur berechnen kann. Dies ist der Grund, warum die meisten Leute mit falsch geschriebenem Code davonkommen - weil der Compiler die Adressierung bestimmen kann. Das Problem tritt auf, wenn jemand versucht, etwas voranzutreiben, z. B. eine Warteschlange oder eine verknüpfte Liste, oder wenn eine O/S-Struktur gepuffert wird.

Eine Deklaration beginnt mit 'struct', eine Definition beginnt mit 'typedef'.

Darüber hinaus verfügt eine Struktur über ein Forward-Deklarations-Label und ein definiertes Label. Die meisten Leute wissen das nicht und verwenden das Forward-Deklarations-Label als definiertes Label.

Falsch:

struct myStruct
   {
   int field_1;
   ...
   };

Sie haben gerade die Forward-Deklaration verwendet, um die Struktur zu kennzeichnen - dem Compiler ist dies also jetzt bekannt -, aber es handelt sich nicht um einen tatsächlich definierten Typ. Der Compiler kann die Adressierung berechnen - aber dies ist aus Gründen, die ich kurz zeigen werde, nicht die beabsichtigte Verwendung.

Leute, die diese Form der Deklaration verwenden, müssen praktisch in jedem Verweis auf sie immer "struct" setzen - weil es sich nicht um einen offiziellen neuen Typ handelt.

Stattdessen sollte jede Struktur, die nicht auf sich selbst verweist, nur so deklariert und definiert werden:

typedef struct
   {
   field_1;
   ...
   }myStruct;

Jetzt ist es ein tatsächlicher Typ, und wenn er verwendet wird, können Sie ihn als 'myStruct' verwenden, ohne das Wort 'struct' voranstellen zu müssen.

Wenn Sie eine Zeigervariable für diese Struktur möchten, fügen Sie eine sekundäre Bezeichnung hinzu:

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

Jetzt haben Sie eine Zeigervariable zu dieser Struktur, die Sie anpassen können.

FORWARD DECLARATION--

Hier ist das ausgefallene Zeug, wie die Forward-Deklaration funktioniert. Wenn Sie einen Typ erstellen möchten, der auf sich selbst verweist, z. B. eine verknüpfte Liste oder ein Warteschlangenelement, müssen Sie eine Forward-Deklaration verwenden. Der Compiler berücksichtigt die definierte Struktur erst, wenn das Semikolon ganz am Ende angekommen ist. Daher wird sie nur vor diesem Punkt deklariert.

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

Jetzt weiß der Compiler, dass er, obwohl er noch nicht weiß, was der gesamte Typ ist, immer noch mit der Vorwärtsreferenz darauf verweisen kann.

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

3
CodeGuru

Im letzteren Beispiel lassen Sie das struct-Schlüsselwort weg, wenn Sie die Struktur verwenden. Sie können also überall in Ihrem Code schreiben:

myStruct a;

anstatt von

struct myStruct a;

Das erspart einiges an Tipparbeit und ist möglicherweise besser lesbar, aber das ist Geschmackssache

2
shodanex