L'idiome commun est d'utiliser les deux :
typedef struct S {
int x;
} S;
Il s'agit de 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 struct (pas au sens de 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 suit struct S
:
void f( struct S argument ); // struct is required here
La deuxième ligne ajoute un alias de type S
dans l'espace global des noms et permet ainsi d'écrire simplement :
void f( S argument ); // struct keyword no longer needed
Notez que puisque les deux espaces de noms d'identifiants sont différents, la définition de S
à la fois dans les espaces structs et global n'est pas une erreur, car il ne s'agit pas de redéfinir le même identifiant, mais plutôt de créer un identifiant différent à un endroit différent.
Pour que la différence soit 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 que la structure car 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 subtilement changé. Le C++ conserve les deux espaces d'identification différents, mais contrairement au C, lorsque vous définissez le symbole uniquement dans l'espace d'identification de classe, 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
Ce qui change, ce sont les règles de recherche, et non l'endroit où les identifiants sont définis. Le compilateur va chercher dans la table des identificateurs globaux et après S
n'a pas été trouvé, il cherchera S
dans les identifiants de classe.
Le code présenté précédemment 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
dans la deuxième ligne, la fonction struct S
ne peuvent pas être résolus automatiquement par le compilateur, et pour créer un objet ou définir un argument de ce type, vous devez revenir à l'inclusion de la balise struct
mot-clé :
// previous code here...
int main() {
S();
struct S s;
}
0 votes
Je viens de lire, ici sur SO, que la deuxième option donnerait une erreur de compilateur ? ! "passage d'un argument de type pointeur incompatible" stackoverflow.com/questions/12708897/
8 votes
On peut trouver une meilleure réponse (à mon avis) aquí .