Quelle est la manière syntaxiquement appropriée de déclarer une structure C?

J’ai déjà vu des structures C déclarées de différentes manières. Pourquoi est-ce et qu’est-ce que chacun fait différemment?

Par exemple:

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

Eh bien, la différence évidente est démontrée dans votre main :

 struct foo a; bar b; baz c; 

La première déclaration est celle d’une struct non typedef et nécessite le mot struct clé struct à utiliser. La seconde est d’une struct anonyme typedef ed, nous utilisons donc le nom typedef . Le troisième combine le premier et le second: votre exemple utilise baz (ce qui est commodément court) mais pourrait tout aussi bien utiliser struct _baz dans le même sens.

Mise à jour: la réponse de larsmans mentionne un cas plus courant dans lequel vous devez utiliser au moins struct x { } pour créer une liste chaînée. Le second cas ne serait pas possible ici (à moins que vous abandonniez la santé mentale et que vous utilisiez un void * place) car la struct est anonyme et que le typedef ne se produit pas tant que la struct n’est pas définie, ce qui ne vous donne aucun moyen de créer un type. safe) pointeur vers le type de struct lui-même. La première version fonctionne bien pour cet usage, mais la troisième est généralement préférée dans mon expérience. Donnez-lui un représentant pour cela.

Une différence plus subtile concerne l’emplacement des espaces de noms. En C, les balises struct sont placées dans un espace de noms distinct des autres noms, mais les noms typedef ne le sont pas. Donc ce qui suit est légal:

 struct test { // contents }; struct test *test() { // contents } 

Mais ce qui suit n’est pas le cas, car le test nom serait ambigu:

 typedef struct { // contents } test; test *test() { // contents } 

typedef raccourcit le nom (toujours un plus), mais le place dans le même espace de noms que vos variables et fonctions. Habituellement, ce n’est pas un problème, mais c’est une différence subtile au-delà du simple raccourcissement.

C’est en grande partie une question de préférence personnelle. J’aime donner aux nouveaux types un nom commençant par une majuscule et omettre la struct . C’est pourquoi j’écris habituellement typedef struct { ... } Foo . Cela signifie que je ne peux pas alors écrire struct Foo .

L’exception est quand une struct contient un pointeur sur son propre type, par exemple

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

Dans ce cas, vous devez également déclarer le type struct Node , car la typedef n’est pas dans la scope de la définition de struct . Notez que les deux noms peuvent être identiques (je ne suis pas sûr de l’origine de la convention de soulignement, mais j’imagine que les anciens compilateurs C ne pouvaient pas gérer la typedef struct XX; ).

Toutes vos utilisations sont syntaxiquement correctes. Je préfère l’usage suivant

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

Notez que cela permet facilement d’utiliser le typedef déjà dans la déclaration de la struct elle struct même, et que même pour la struct qui se référencent mutuellement.

La confusion vient du fait que certaines déclarations déclarent jusqu’à trois constructions C. Vous devez garder à l’esprit la différence entre: 1. Une déclaration typedef, 2. Une définition de structure et 3. Une déclaration de structure.

Ce sont tous des constructions C très différentes. Ils font tous des choses différentes. mais vous pouvez les combiner dans la construction à composé unique, si vous le souhaitez.

Regardons chaque déclaration à tour de rôle.

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

Nous utilisons ici la syntaxe de définition de structure la plus élémentaire. Nous définissons foo comme un type C pouvant ensuite être utilisé pour déclarer des variables de ce type à l’aide de la syntaxe suivante:

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

// ============================================= ==== Cette déclaration suivante est un peu similaire à la syntaxe précédente en ce sens qu’elle déclare un type C, mais utilise la syntaxe typedef. Découpons-le en ses composants en utilisant la déclaration de base précédente.

 typedef foo bar; // Declare bar as a variable type, the alias of foo. bar myBar; // This is ssemantically the same as: foo myBar; 

Maintenant, remplacez simplement le “foo” par la syntaxe précédente et le tour est joué!

 typedef struct { short d; int e; float f; } bar; //================================================================== typedef struct _baz { short a; int b; float c; } baz; 

La syntaxe ci-dessus est équivalente à la séquence de déclarations suivante.

 struct _baz { short a; int b; float c; } typedef _baz baz; // Declare baz as an alias for _baz. baz myBaz; // Is the same as: _baz myBaz; //========================================================