2011-01-15 4 views
28

Ich habe C-Structs schon mehrere verschiedene Arten erklärt. Warum ist das und was, wenn überhaupt, macht jedes etwas anderes?Was ist der syntaktisch korrekte Weg, eine C-Struktur zu deklarieren?

Zum Beispiel:

struct foo { 
    short a; 
    int b; 
    float c; 
}; 

typedef struct { 
    short d; 
    int e; 
    float f; 
} bar; 

typedef struct _baz { 
    short a; 
    int b; 
    float c; 
} baz; 

int main (int argc, char const *argv[]) 
{ 
    struct foo a; 
    bar b; 
    baz c; 

    return 0; 
} 
+0

Dies beantwortet nicht Ihre Frage für C, aber ich glaube, sie sind alle korrekt für C++, obwohl die erste bevorzugt wird. Das mag sich auch zwischen verschiedenen Versionen von C geändert haben, aber ich werde jemand anderen damit sprechen lassen, da ich kein Experte für die Geschichte von C/C++ bin. –

+2

C++ ist anders: Wenn Sie 'struct Foo {};' oder 'class Foo {};' dort schreiben, erhalten Sie 'Foo' kostenlos ohne' typedef'. –

+0

Sie werden immer noch funktionieren, auch wenn sie etwas andere Dinge tun (wie den Namespace mit zusätzlichen Tags verschmutzen). –

Antwort

31

Nun, der offensichtliche Unterschied in Ihrem main demonstriert:

struct foo a; 
bar b; 
baz c; 

Die erste Erklärung ist ein un- typedef ed struct und benötigt das struct Schlüsselwort zu verwenden. Die zweite ist eine typedef ed anonyme struct, und so verwenden wir den typedef Namen. Die dritte kombiniert sowohl die erste als auch die zweite: Ihr Beispiel verwendet baz (was kurz ist), könnte aber genauso gut struct _baz mit demselben Effekt verwenden.

Update: larsmans' answer erwähnt einen häufigeren Fall, in dem Sie mindestens struct x { } verwenden müssen, um eine verkettete Liste zu erstellen. Der zweite Fall wäre hier nicht möglich (es sei denn, Sie verzichten auf Vernunft und verwenden stattdessen eine void *), weil die struct anonym ist, und die typedef nicht passiert, bis die struct definiert ist, so dass Sie keine Möglichkeit haben, ein (typsicheres)) Zeiger auf den struct Typ selbst. Die erste Version funktioniert gut für diese Verwendung, aber die dritte wird meiner Erfahrung nach bevorzugt. Gib ihm dafür ein paar Worte.

Ein feinerer Unterschied liegt in der Namespace-Platzierung. In C werden struct Tags in einem separaten Namespace von anderen Namen platziert, aber typedef Namen sind nicht. So ist die folgende Rechts:

struct test { 
    // contents 
}; 

struct test *test() { 
    // contents 
} 

Aber die folgende ist nicht, weil es eindeutig ist, was der Name test ist:

typedef struct { 
    // contents 
} test; 

test *test() { 
    // contents 
} 

typedef der Name kürzer macht (immer ein Pluspunkt), aber es fügt es in denselben Namensraum ein wie Ihre Variablen und Funktionen. Normalerweise ist das kein Problem, aber es ist ein subtiler Unterschied, der über die einfache Verkürzung hinausgeht.

+0

Große Antwort, danke! –

+0

+1 für das Namespace-Problem. –

+0

Würde die Verwendung des gleichen Namens für das Tag und das Typedef ungültig sein? Oder keine gute Idee? Oder ist das vollkommen in Ordnung? Zum Beispiel: typedef struct mystruct {} mystruct; – SeanRamey

27

Es ist weitgehend eine Frage des persönlichen Geschmacks. Ich möchte neuen Typen einen Namen geben, der mit einem Großbuchstaben beginnt und die struct weglässt, so schreibe ich normalerweise typedef struct { ... } Foo. Das heißt, ich kann dann nicht struct Foo schreiben.

Die Ausnahme ist, wenn ein struct einen Zeiger auf seinen eigenen Typ enthält, z.

typedef struct Node { 
    // ... 
    struct Node *next; 
} Node; 

In diesem Fall müssen Sie auch die struct Node Art erklären, da die typedef in ihrem Umfang nicht innerhalb der struct Definition. Beachten Sie, dass beide Namen identisch sein können (ich bin mir nicht sicher, woher die Unterstreichungskonvention stammt, aber ich denke, ältere C-Compiler konnten nicht mit typedef struct X X; umgehen).

+0

Doh! Ich habe den offensichtlichen Anwendungsfall "Linked List" vergessen. +1 –

6

Alle Ihre Anwendungen sind syntaktisch korrekt.Ich ziehe es folgende Nutzungs

/* forward declare all structs and typedefs */ 
typedef struct foo foo; 
. 
. 
/* declare the struct itself */ 
struct foo { 
    short a; 
    int b; 
    foo* next; 
}; 

Beachten Sie, dass dies leicht die typedef bereits in der Erklärung des struct selbst, und dass auch für struct, die einander gegenseitig Referenz verwenden können.

+3

+1 für einen Bereich, den ich vermisste, und fügen hinzu, dass, wenn Sie 'typedef struct foo foo;' in Ihren Headern verwenden und keine Definition von 'struct foo' bereitstellen, Benutzercode einen undurchsichtigen Zeiger (dh sie können übergeben werden 'foo *' Zeiger auf und erhalten sie von Bibliotheksfunktionen, aber können nicht auf die internen Mitglieder zugreifen.) Dies ist gut für die Datenkapselung und ein allgemeines Idiom: der Standard 'FILE *' Typ ist eine solche Instanz davon. –

4

Die Verwirrung kommt zustande, weil einige der Deklarationen tatsächlich bis zu drei C-Konstrukte deklarieren. Sie müssen den Unterschied beachten zwischen: 1. Eine typedef-Deklaration, 2. Eine Strukturdefinition und 3. Eine Struktur Deklaration.

Sie sind alle sehr unterschiedliche C-Konstrukte. Sie alle machen verschiedene Dinge; aber Sie können sie in das eine zusammengesetzte Konstrukt kombinieren, wenn Sie möchten.

Schauen wir uns nacheinander jede Erklärung an.

//================================================ 
struct foo { 
    short a; 
    int b; 
    float c; 
}; 

Hier verwenden wir die grundlegendste Syntax für die Strukturdefinition. Wir definieren foo als C Typen, die später verwendet werden können Variablen dieses Typs mit folgenden Syntax zu erklären:

foo myFoo; // Declare a struct variable of type foo. 

// =============== ================================== Diese nächste Deklaration ist ein bisschen wie die vorherige Syntax darin Es deklariert einen C-Typ, aber es verwendet die Typedef-Syntax. Lassen Sie es uns anhand der vorherigen Basisdeklaration in seine Komponenten aufteilen.

Jetzt ersetzen Sie einfach die "foo" mit der vorherigen Syntax und voila!

typedef struct { 
    short d;  
    int e; 
    float f; 
} bar; 

//================================================================== 
typedef struct _baz { 
    short a; 
    int b; 
    float c; 
} baz; 

Die obige Syntax entspricht der folgenden Deklarationsfolge.

Verwandte Themen