typedef struct vs struct définitions [dupliquer]

cette question a déjà une réponse ici:

je suis un débutant en programmation C, mais je me demandais quelle était la différence entre utiliser typedef lors de la définition d'une structure et ne pas utiliser typedef. Il me semble moi comme il n'y a vraiment aucune différence, ils accomplissent la même chose.

struct myStruct{
    int one;
    int two;
};

vs.

typedef struct{
    int one;
    int two;
}myStruct;
653
demandé sur OmG 2009-11-04 20:21:57
la source

12 ответов

l'idiome commun utilise les deux:

typedef struct X { 
    int x; 
} X;

ce sont des définitions différentes. Pour rendre la discussion plus claire, je vais diviser la phrase:

struct S { 
    int x; 
};

typedef struct S S;

dans la première ligne vous définissez l'identifiant S dans l'espace de nom de structure (pas dans le sens C++). Vous pouvez l'utiliser et définir des variables ou des arguments de fonction du type nouvellement défini en définissant le type de l'argument comme struct S :

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

la deuxième ligne ajoute un alias de type S dans l'Espace nom global et vous permet donc d'écrire simplement:

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

noter que puisque les deux espaces de nom d'identifiant sont différents, définir S à la fois dans les structures et les espaces globaux n'est pas une erreur, car il ne redéfinit pas le même identifiant, mais plutôt de créer un identifiant différent dans un endroit différent.

pour faire la différence:

typedef struct S { 
    int x; 
} T;

void S() { } // correct

//void T() {} // error: symbol T already defined as an alias to 'struct S'

vous pouvez définir une fonction avec le même nom de la structure que les identificateurs sont conservés dans des espaces différents, mais vous ne pouvez pas définir une fonction avec le même nom qu'un typedef car ces identificateurs entrent en collision.

en C++, il est légèrement différent car les règles pour localiser un symbole ont changé subtilement. C++ conserve toujours les deux espaces d'identification différents, mais contrairement à C, lorsque vous définissez seulement le symbole dans l'Identificateur de classe space, vous n'êtes pas tenu de fournir le mot-clé struct/class:

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

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

quelles sont les modifications apportées aux règles de recherche, et non à l'endroit où les désignations sont définies? Le compilateur effectuera une recherche dans la table des identificateurs globaux et, après que S n'aura pas été trouvé, il recherchera S dans les identificateurs de classe.

le code présenté avant se comporte de la même manière:

typedef struct S { 
    int x; 
} T;

void S() {} // correct [*]

//void T() {} // error: symbol T already defined as an alias to 'struct S'

Après la définition de la S fonction dans la deuxième ligne, les structures ne peuvent pas être résolues automatiquement par le compilateur, et pour créer un objet ou définir un argument de ce type, vous devez revenir à inclure le struct mot-clé:

// previous code here...
int main() {
    S(); 
    struct S s;
}
820
répondu David Rodríguez - dribeas 2016-03-04 23:40:30
la source

struct et typedef sont deux choses très différentes.

le mot-clé struct est utilisé pour définir, ou se référer à, un type de structure. Par exemple, ceci:

struct foo {
    int n;
};

crée un nouveau type appelé struct foo . Le nom foo est un étiquette ; il est significatif seulement quand il est immédiatement précédé par le mot-clé struct , parce que les étiquettes et d'autres identificateurs sont en distinct espaces de nom . (Ceci est similaire, mais beaucoup plus restreint que le concept C++ de namespace s.)

A typedef , malgré le nom, ne définit pas un nouveau type; il crée simplement un nouveau nom pour un type existant. Par exemple:

typedef int my_int;

my_int est un nouveau nom pour int ; my_int et int sont exactement le même type. De même, compte tenu du struct définition ci-dessus, vous pouvez écrire:

typedef struct foo foo;

le type a déjà un nom, struct foo . La déclaration typedef donne au même type un nouveau nom, foo .

la syntaxe vous permet de combiner un struct et typedef en une seule déclaration:

typedef struct bar {
    int n;
} bar;

c'est un langage courant. Maintenant, vous pouvez vous référer à ce type de structure soit comme struct bar ou tout simplement comme bar .

notez que le nom typedef ne devient visible qu'à la fin de la déclaration. Si la structure contient un pointeur vers elle-même, vous devez utiliser la version struct pour s'y référer:

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

certains programmeurs utiliseront des identificateurs distincts pour la balise struct et pour le nom typedef. À mon avis, il n'y a pas de bonne raison pour cela; utiliser le même nom est parfaitement légal et rend plus clair qu'ils sont du même type. Si vous devez utiliser différents identificateurs, au moins utiliser une convention cohérente:

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

(personnellement, je préfère omettre le typedef et faire référence au type comme struct bar . Le typedef sauve un peu de Dactylographie, mais il cache le fait qu'il est un type de structure. Si vous souhaitez que le type opaque, cela peut être une bonne chose. Si le code client se réfère au membre n par son nom, alors il n'est pas opaque; c'est visiblement une structure, et à mon avis il fait sens de s'y référer comme une structure. Mais beaucoup de programmeurs intelligents en désaccord avec moi sur ce point. Se préparer à lire et comprendre le code écrit.)

(C++ a des règles différentes. Avec une déclaration de struct blah , vous pouvez vous référer au type comme juste blah , même sans un typedef. Utiliser un typedef pourrait rendre votre code C un peu plus C++-comme -- si vous pensez que c'est une bonne chose.)

93
répondu Keith Thompson 2014-10-15 22:02:29
la source

une autre différence non signalée est que donner un nom à la struct (i.e. struct myStruct) vous permet également de fournir des déclarations forward de la struct. Donc dans un autre fichier, vous pourriez écrire:

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

sans avoir à accéder à la définition. Je vous recommande de combiner vos deux exemples:

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

cela vous donne la commodité du nom dactylographié plus concis mais vous permet tout de même d'utiliser le plein struct name si vous avez besoin.

85
répondu R Samuel Klatchko 2014-10-28 19:34:36
la source

en C (Pas C++), vous devez déclarer les variables struct comme:

struct myStruct myVariable;

afin de pouvoir utiliser myStruct myVariable; à la place, vous pouvez typedef la structure:

typedef struct myStruct someStruct;
someStruct myVariable;

Vous pouvez combiner "151950920 définition" et typedef s dans une seule instruction qui déclare un anonyme struct et typedef s il.

typedef struct { ... } myStruct;
50
répondu Mehrdad Afshari 2009-11-04 20:25:53
la source

si vous utilisez struct sans typedef , vous devrez toujours écrire

struct mystruct myvar;

il est illégal d'écrire

mystruct myvar;

si vous utilisez le typedef vous n'avez plus besoin du préfixe struct .

24
répondu RED SOFT ADAIR 2017-04-10 16:36:08
la source

en C, les mots-clés spécifiant le type des structures, des syndicats et des énumérations sont obligatoires, c'est-à-dire que vous devez toujours préfixer le nom du type (son étiquette ) avec struct , union ou enum lorsque vous faites référence au type.

vous pouvez vous débarrasser des mots-clés en utilisant un typedef , qui est une forme d'information se cachant que le type réel d'un objet ne sera plus visible lors de sa déclaration.

il est par conséquent recommandé (voir par exemple le Linux kernel coding style guide , Chapitre 5) de ne le faire que lorsque vous réellement voulez pour cacher cette information et pas seulement pour sauver quelques touches.

un exemple de cas où vous devez utiliser un typedef serait un type opaque qui n'est utilisé qu'avec les fonctions d'accesseur/macros correspondantes.

22
répondu Christoph 2011-11-05 19:39:17
la source

La différence lorsque vous utilisez le struct .

La première façon que vous avez à faire:

struct myStruct aName;

la deuxième voie vous permet de supprimer le mot-clé struct .

myStruct aName;
5
répondu jjnguy 2009-11-04 20:26:47
la source

vous ne pouvez pas utiliser la déclaration forward avec le typedef struct .

le struct lui-même est un type anonyme, donc vous n'avez pas un nom réel à transmettre déclarer.

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

une telle déclaration ne marchera pas:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types
5
répondu Yochai Timmer 2017-04-10 16:35:09
la source

le typedef , comme avec d'autres constructions, est utilisé pour donner un nouveau nom à un type de données. Dans ce cas, il est principalement fait afin de rendre le code plus propre:

struct myStruct blah;

vs.

myStruct blah;
4
répondu RC. 2009-11-04 20:42:55
la source

le code suivant crée une structure anonyme avec l'alias myStruct :

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

vous ne pouvez pas le renvoyer sans l'alias car vous ne spécifiez pas d'identifiant pour la structure.

4
répondu Wronski 2017-04-10 16:35:40
la source

je vois certaines précisions sont dans l'ordre sur cette. C et c++ ne définissent pas les types différemment. C++ n'était à l'origine rien de plus qu'un ensemble supplémentaire d'inclusions sur C.

le problème que pratiquement tous les développeurs C/C++ ont aujourd'hui, est a) les universités n'enseignent plus les fondamentaux, et b) les gens ne comprennent pas la différence entre une définition et une déclaration.

est la seule raison pour laquelle ces déclarations et définitions exist permet au linker de calculer les offsets d'adresses sur les champs de la structure. C'est pourquoi la plupart des gens s'en tirent avec du code qui est en fait écrit incorrectement-- parce que le compilateur est capable de déterminer l'adresse. Le problème se pose quand quelqu'un essaie de faire quelque chose d'avance, comme une file d'attente, ou une liste liée, ou piggying-backing une structure O/s.

Une déclaration commence par "struct", définition commence par "typedef'.

en outre, a struct a un label forward declaration, et un label défini. La plupart des gens ne le savent pas et utilisent l'étiquette forward declaration comme une étiquette define.

Mauvais:

struct myStruct
   {
   int field_1;
   ...
   };

ils viennent d'utiliser la déclaration forward pour étiqueter la structure-- donc maintenant le compilateur en est conscient-- mais ce n'est pas un type défini réel. Le compilateur peut calculer l'adressage-- mais ce n'est pas comme ça qu'il a été conçu pour être utilisé, pour des raisons que je vais montrer momentanément.

les gens qui utilisent cette forme de déclaration, doivent toujours mettre 'struct' en pratique chaque référence à elle-parce qu'il n'est pas un nouveau type officiel.

au lieu de cela, toute structure qui ne se réfère pas elle-même, devrait être déclarée et définie de cette façon seulement:

typedef struct
   {
   field_1;
   ...
   }myStruct;

Maintenant, c'est un type réel, et si vous pouvez l'utiliser comme 'myStruct", sans avoir à préfixer avec le mot 'struct'.

si vous voulez une variable pointeur vers cette structure, puis inclure une étiquette secondaire:

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

Maintenant vous avez une variable de pointeur à cette structure, personnalisée à elle.

FORWARD DECLARATION--

maintenant, voici le truc fantaisiste, comment fonctionne la déclaration forward. Si vous voulez créer un type qui se réfère à lui-même, comme une liste liée ou un élément de file d'attente, vous devez utiliser une déclaration forward. Le compilateur ne considère pas la structure définie jusqu'à ce qu'il atteigne le point-virgule à la fin, il est donc juste déclaré avant ce point.

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

maintenant, le compilateur sait que bien qu'il ne sache pas encore ce qu'est le type entier, il peut encore le référencer en utilisant la référence forward.

veuillez déclarer et dactylographier correctement vos structures. Il y a en fait une raison.

3
répondu CodeGuru 2015-06-12 21:30:36
la source

dans ce dernier exemple, vous omettez le mot-clé struct lorsque vous utilisez la structure. Donc partout dans votre code, vous pouvez écrire :

myStruct a;

au lieu de

struct myStruct a;

cela économise un peu de Dactylographie, et pourrait être plus lisible, mais c'est une question de goût

1
répondu shodanex 2009-11-04 20:27:34
la source

Autres questions sur c struct typedef