Question 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 est la différence entre l'utilisation de typedef lors de la définition d'une structure et la non utilisation de typedef. Il me semble qu'il n'y a vraiment aucune différence, ils accomplissent la même chose.

struct myStruct{
    int one;
    int two;
};

contre.

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

634
2017-11-04 17:21


origine


Réponses:


L'idiome commun utilise à la fois:

typedef struct X { 
    int x; 
} X;

Ce sont des définitions différentes. Pour clarifier la discussion, je vais scinder 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 la structure (pas au 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 de nom global et vous permet ainsi d'écrire:

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

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

Pour rendre la différence plus claire:

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 identifiants 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 lorsque ces identifiants entrent en collision.

En C ++, c'est légèrement différent car les règles pour localiser un symbole ont changé subtilement. C ++ conserve toujours les deux espaces d'identificateur différents, mais contrairement à C, lorsque vous définissez uniquement le symbole dans l'espace d'identificateur de classe, vous n'êtes pas obligé 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

Quels changements sont les règles de recherche, pas où les identificateurs sont définis. Le compilateur recherchera dans la table d'identificateur global et après S n'a pas été trouvé, il va chercher S dans les identifiants 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 du S fonction dans la deuxième ligne, la structure S ne peut pas être résolue 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;
}

800
2017-11-04 17:37



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

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

struct foo {
    int n;
};

crée un nouveau type appelé struct foo. Le nom foo est un marque; il est significatif seulement quand il est immédiatement précédé par le struct mot clé, car les tags et autres identifiants sont distincts espaces de noms. (Ceci est similaire à, mais beaucoup plus restreint que, le concept C ++ de namespaces.)

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

typedef int my_int;

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

typedef struct foo foo;

Le type a déjà un nom, struct foo. le typedef déclaration donne un nouveau nom au même type, 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 idiome commun. Vous pouvez maintenant vous référer à ce type de structure struct bar ou juste comme bar.

Notez que le nom typedef ne devient pas visible jusqu'à la fin de la déclaration. Si la structure contient un pointeur, vous avez utilisé le struct la version 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 identifiants distincts pour la balise struct et pour le nom typedef. À mon avis, il n'y a pas de bonne raison à 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 des identifiants différents, utilisez au moins une convention cohérente:

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

(Personnellement, je préfère omettre le typedef et se référer au type comme struct bar. le typedef sauvez un peu de frappe, mais cela cache le fait que c'est un type de structure. Si vous voulez que le type soit opaque, cela peut être une bonne chose. Si le code client fait référence au membre n par son nom, alors ce n'est pas opaque; c'est visiblement une structure et, à mon avis, il est logique de parler de structure. Mais beaucoup de programmeurs intelligents ne sont pas d'accord avec moi sur ce point. Soyez prêt à lire et à comprendre le code écrit dans les deux sens.)

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


86
2017-10-15 18:02



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

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

sans avoir à avoir accès à la définition. Ce que je recommande, c'est de combiner vos deux exemples:

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

Cela vous donne la commodité du nom de typedef plus concis mais vous permet quand même d'utiliser le nom de structure complet si vous en avez besoin.


85
2017-11-04 17:49



En C (pas C ++), vous devez déclarer des variables struct comme:

struct myStruct myVariable;

Afin de pouvoir utiliser myStruct myVariable; Au lieu de cela, vous pouvez typedef la structure:

typedef struct myStruct someStruct;
someStruct myVariable;

Vous pouvez combiner struct définition et typedefs dans une déclaration unique qui déclare un anonyme struct et typedefasseoir.

typedef struct { ... } myStruct;

50
2017-11-04 17:25



En C, les mots-clés de spécification de type des structures, des unions et des énumérations sont obligatoires, c'est-à-dire que vous devez toujours préfixer le nom du type (son marque) avec struct, union ou enum en se référant au type.

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

Il est donc recommandé (voir par exemple le Guide de codage du noyau Linux, Chapitre 5) pour ne le faire que lorsque vous avez réellement vouloir cacher cette information et pas seulement pour sauvegarder quelques frappes.

Un exemple de quand vous devriez utiliser un typedef serait un type opaque qui n'est utilisé qu'avec des fonctions / macros accesseurs correspondantes.


22
2017-11-04 17:46



Si tu utilises struct sans pour autant typedef, tu devras toujours écrire

struct mystruct myvar;

C'est illégal d'écrire

mystruct myvar;

Si vous utilisez le typedef vous n'avez pas besoin de struct préfixe plus.


22
2017-11-04 17:26



La différence entre lorsque vous utilisez le struct.

La première façon que vous devez faire:

struct myStruct aName;

La deuxième façon vous permet de supprimer le mot-clé struct.

myStruct aName;

5
2017-11-04 17:26



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 de nom réel à transmettre.

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

Une déclaration forward comme celle-ci ne fonctionnera pas:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

5
2017-08-05 09:17



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

struct myStruct blah;

contre.

myStruct blah;

4
2017-11-04 17:24