54 votes

Quelle est la signification de `struct X typedef` par rapport à` typedef struct X`?

J'ai le code (de travail) suivant dans une base de code existante, utilisé dans un fichier inclus partagé entre C et C ++, en compilant sur MSVC (2010) et Windows DDK:

 struct X {
    USHORT x;
} typedef X, *PX;
 

Et:

 enum MY_ENUM {
    enum_item_1,
    enum_item_2 
} typedef MY_ENUM;
 

Pour autant que je sache, une définition correcte devrait ressembler à ceci:

 typedef struct {
    USHORT x;
} X, *PX;
 

Le formulaire ci-dessous a-t-il une utilité? Est-ce que je manque quelque chose?

56voto

Oli Charlesworth Points 148744

Le fait que les deux typedef <type> <alias> et <type> typedef <alias> sont valables vient tout simplement de la langue grammaire définition.

typedef est classé comme un stockage de classe specfifier (comme static, auto), et le type lui-même est connu comme le type spécificateur. À partir de la syntaxe des définitions dans la section 6.7 de la norme, vous verrez que ce sont de libre-échange:

declaration:
    declaration-specifiers init-declarator-list ;

declaration-specifiers:
    storage-class-specifier declaration-specifiers
    type-specifier declaration-specifiers
    type-qualifier declaration-specifiers
    function-specifier declaration-specifiers

init-declarator-list:
    init-declarator
    init-declarator-list , init-declarator

init-declarator:
    declarator
    declarator = initializer

(Remarque, bien sûr, que c'est également vrai pour les structures et pour les non-structs, ce qui signifie qu' double typedef trouble; est également valide.)

18voto

ouah Points 75311

Comme les autres ont dit, typedef est un espace de stockage de classe spécificateur et comme avec d'autres de stockage de classe spécificateurs vous êtes également autorisé à mettre le spécificateur entre le type et le jugement de nullité.

Tout ceci est valable et c'est aussi une forme qui doit être évitée, comme C marqué comme la vétusté des fonctionnalité:

(C11, 6.11.5p1) "Le placement d'une catégorie de stockage spécificateur d'autres qu'au début de la déclaration des prescripteurs dans une déclaration à l'est de la vétusté des fonctionnalité."

6voto

haccks Points 33022

Les deux ont la même signification. Les deux formes sont valides:

 typedef <existing_type> <new_type>
<existing_type> typedef <new_type>   
 

Vous pouvez typedef la structure ci-dessus de deux manières:

 struct X {
    USHORT x;
}typedef X, *PX;     // <existing_type> typedef <new_type> 
 

ou

 typedef struct {
    USHORT x;
} X, *PX;            // typedef <existing_type> <new_type>
 

5voto

librik Points 2256

Vraiment vous êtes autorisé à mettre ensemble la déclaration des prescripteurs dans n'importe quel ordre que vous voulez! Les positions de quelque * des pointeurs et le réel de demande de déclaration (la variable ou d'un type nouveau nom), mais tout ce que l' typedef int unsigned const static etc. des choses peut être dans n'importe quel ordre.

Si vous regardez l'officiel de la grammaire de C, il dit seulement:

declaration:
    declaration-specifiers init-declarator-list ;

L' declaration-specifiers sont tous de la classe de stockage de prescripteurs (typedef, extern, etc.), spécificateurs de type (le type réel, comme int ou struct X), de type qualificatifs (const et volatile), et quelques autres moins courantes. Leur ordre n'est pas important. La deuxième partie est l' init-declarator-list, et c'est la variable ou d'un type nouveau nom (dans le cas d'un typedef), tout * personnages, l'initialisation de la variable (int x = 3), et plus encore. L'ordre des choses dans la déclaration de partie est importante, mais pas l'ordre dans la déclaration des prescripteurs.

5voto

LumpN Points 2989

Avertissement: Ce n'est pas une technique mais une réponse pratique. Voir les réponses pour les questions techniques. Cette réponse se lit opiniâtre et subjective, mais s'il vous plaît garder avec moi pendant que j'essaie d'expliquer l'image plus grande.

struct est une drôle de bête, parce que les trucs que vous mettez entre la parenthèse fermante } et le point-virgule ; désigne le contenu à l'intérieur ou à l'avant de ces crochets. Je sais pourquoi, et grammaticalement, il est logique, mais personnellement, je trouve qu'il est très contre-intuitif que les accolades signifie généralement portée:

Contre-intuitive, exemples:

// declares a variable named `foo` of unnamed struct type.
struct {
    int x, y;
} foo;

foo.x = 1;


// declares a type named `Foo` of unnamed struct type
struct {
    int x, y;
} typedef Foo;

Foo foo2;
foo2.x = 2;


// declares a type named `Baz` of the struct named `Bar`
struct Bar {
    int x, y;
} typedef Baz;

// note the 'struct' keyword to actually use the type 'Bar'
struct Bar bar;
bar.x = 3;
Baz baz;
baz.x = 4;

Il y a tellement de belles choses qui peuvent mal se passer avec la dense syntaxe de l' structs et typedefs s'utilise comme ceci. Comme indiqué ci-dessous, il est très facile de déclarer une variable au lieu d'un type par accident. Le compilateur est que de peu d'aide parce que presque toutes les combinaisons sont grammaticalement correctes. Ils ne sont pas nécessairement ce que vous essayez d'exprimer. C'est un abîme de désespoir.

Mauvais exemples:

// mixed up variable and type declaration
struct foo {
    int x, y;
} Foo;

// declares a type 'foo' instead of a variable
typedef struct Foo {
    int x, y;
} foo;

// useless typedef but compiles fine
typedef struct Foo {
    int x, y;
};

// compiler error
typedef Foo struct {
    int x, y;
};

Pour des raisons de lisibilité et de la maintenance, je préfère déclarer tout séparément et ne jamais mettre quoi que ce soit derrière l'accolade fermante. Le coût de lignes de code supplémentaires sont facilement compensés par intuitive de la syntaxe. Je soutiens que cette approche rend plus facile pour faire les bonnes choses et ennuyeux à faire les mauvaises choses.

Intuitive exemples:

// declares a struct named 'TVector2'
struct TVector2 {
    float x, y;
};

// declares a type named 'Vector2' to get rid of the 'struct' keyword
// note that I really never use 'TVector2' afterwards
typedef struct TVector2 Vector2;

Vector2 v, w;
v.x = 0;
v.y = 1;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X