Le nom typedef est-il facultatif dans une déclaration typedef?

J'ai été assez surpris quand j'ai vu le code suivant compiler sans erreurs ou avertissements dans g++-4.2:

typedef enum test { one };

Mon hypothèse était que si vous utilisiez le mot-clé typedef, Il faudrait un identifiant supplémentaire comme dans:

typedef enum test { one } test;

, Comme déjà mentionné, g++-4.2 l'accepte sans même un avertissement. Clang++ 3.0 avertit que "avertissement: typedef nécessite un nom", de même Comeau avertit que "avertissement: déclaration requiert une définition de type de nom de, et g++-4.6 informe: "avertissement: 'typedef' a été ignoré dans cette déclaration ".

Je n'ai pas été en mesure d'identifier où dans la norme cela est autorisé, et je trouve un peu déroutant que deux des compilateurs avertissent qu'il est required, ne devrait-il pas être une erreur si le nom typedef est required mais pas présent?

UPDATE : j'ai vérifié en C avec les mêmes compilateurs. Clang et comeau donnent la même sortie, gcc donne un avertissement: "warning: useless storage class spécificateur dans la déclaration vide ", ce qui semble encore plus déroutant.

UPDATE : j'ai vérifié en supprimant le nom de l'énumération et les résultats sont les mêmes:

typedef enum { one };

De même avec une structure nommée:

typedef struct named { int x };

, Mais pas avec une nouvelle structure, dans lequel cas, le code a été rejetée en g++ (4.2/4.6) avec "erreur: manque de type nom dans la définition de type-déclaration", gcc (4.2/4.6) a donné un avertissement: "avertissement: sans nom struct/union qui définit aucun cas", clang++ "avertissement: déclaration ne rien déclarer", comeau "erreur: déclaration requiert une définition de type de nom de"

31
demandé sur David Rodríguez - dribeas 2011-06-19 04:56:47

3 réponses

C'est une syntaxe dégénérée qui est autorisée mais qui n'apporte aucun avantage. La plupart des compilateurs modernes peuvent être provoqués en émettant un avertissement à ce sujet; par défaut, ils ne peuvent pas. Sans le nom typedef, le mot-clé typedef est superflu; dans votre exemple, il est complètement équivalent à:

enum test { one };

Un autre endroit où cela peut se produire est avec une structure:

typedef struct SomeThing { int whatever; };

, Ceci est équivalent à:

struct SomeThing { int whatever; };

Notez que {[4] } est officiellement (ou syntaxiquement) un 'spécificateur de classe de stockage', comme static, extern, auto et register.


Norme C

Dans ISO / IEC 9899: 1999 (c'est la norme C), on trouve:

§6.7 Déclarations

La Syntaxe

déclaration de:

declaration-specifiers init-declarator-listopt;

declaration-specifiers:

de stockage de classe-rédacteur de devis déclaration spécificateursopt

type-specifier declaration-specifiersopt

type de qualificatif déclaration spécificateursopt

function-specifier declaration-specifiersopt

init-declarator-list:

init-déclaration de

init-declarator-list , init-declarator

init-declarator:

déclaration de

déclaration de = initialiseur

Et (comme demandé):

§6.7.1 spécificateurs de classe de stockage

La Syntaxe

Spécificateur de classe de stockage:

typedef

extern

static

auto

register

Si vous suivez cette syntaxe, il y a beaucoup de possibilités dégénérées, et ce que vous avez montré est juste l'un des nombreux.


Norme C++

Il est possible que C++ ait des règles différentes.

Dans ISO / IEC 14882: 1998 (la norme C++ originale), nous trouvons dans §7.1.1 'spécificateurs de classe de stockage' que C++ ne traite pas typedef comme une classe de stockage; la liste ajoute mutable et exclut typedef. Ainsi, la spécification grammaticale de typedef en c++ est définitivement différente de la spécification C.

§7 déclarations

Les déclarations

Précisent comment les noms doivent être interprétés. Les déclarations ont la forme

Déclaration-seq:

declaration

déclaration-seq déclaration

Déclaration:

block-declaration

fonction-définition

template-declaration

instanciation explicite

explicit-specialization

liaison-spécification

namespace-definition

Block-declaration:

déclaration simple

asm-definition

namespace-alias-définition de

using-declaration

à l'aide de la directive-

Simple-déclaration:

decl-spécificateur-seqopt init-demande de déclaration-listeopt ;

...

¶5 si le spécificateur decl-seq contient le spécificateur typedef, la déclaration est appelée déclaration typedef et le nom de chaque init-declarator est déclaré comme étant un nom typedef, synonyme de son type associé (7.1.3).

§7.1 spécificateurs [dcl.spec]

Le les spécificateurs qui peuvent être utilisés dans une déclaration sont

Spécificateur Decl:

storage-class-specifier

spécificateur de type

function-specifier

friend

typedef

Decl-spécificateur-seq:

decl-specifier-seqopt

Decl-spécificateur

§7.1.1 spécificateurs de classe de stockage [dcl .stc]

Spécificateur de classe de stockage:

auto

register

static

extern

mutable

§7.1.2 spécificateurs de fonction [dcl.fct.spec]

Fonction-spécificateur:

inline

virtual

explicit

§7.1.3 le spécificateur typedef [dcl.typedef]

Déclarations contenant le spécificateur decl typedef déclarer les identifiants qui peuvent être utilisés plus tard pour nommer types fondamentaux (3.9.1) ou composés (3.9.2). Le spécificateur typedef ne doit pas être utilisé dans une définition de fonction (8.4), et il ne doit pas être combiné dans un Decl-spécificateur-seq avec tout autre type de spécificateur sauf un spécificateur de type.

Typedef-nom:

identifier

...

In a given scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers. [Example:

{[3]}

—end example]

§7.1.4 The friend specifier [dcl.friend]

The friend specifier is used to specify access to class members; see 11.4.

§7.1.5 Type specifiers [dcl.type]

Type-specifier:

spécificateur de type simple

class-specifier

enum spécificateur de

elaborated-type-specifier

cv-qualificateur


, Puisque §7 ¶5 dit que typedef noms proviennent de la init-déclaration de et le init-demande de déclaration-liste est marqué 'opt', je pense que cela signifie que le typedef nom peut être omis en C++, tout comme en C.

39
répondu Jonathan Leffler 2011-06-19 10:38:26

La seule chose que j'ai pu trouver était la suivante dans la norme C++03 §7.1.3 [dcl.typedef] p1:

typedef-nom:

  • identificateur

Un nom déclaré à l' typedef spécificateur devient un typedef-nom.

Notez le manque opt après identificateur, ce qui indique, au moins pour moi, qu'un identificateur est nécessaire pour la typedef-nom. Étrange que tous les les compilateurs testés (silencieusement) l'acceptent.


Edit : après la réponse de @Jonathan, j'ai trouvé ce qui suit dans la même norme que ci-dessus:

Decl-spécificateur :

  • spécificateur de classe de stockage
  • spécificateur de type
  • spécificateur de fonction
  • friend
  • typedef

Comme on peut le voir, il fournit un cas supplémentaire pour typedef et la liste sur spécificateurs de classe de stockage confirme ceci:

Spécificateur de classe de stockage:

  • auto
  • register
  • static
  • extern
  • mutable

Donc, nous sommes aussi désemparés qu'avant dans le cas C++.

3
répondu Xeo 2011-06-19 01:36:08

Cela ressemble vraiment à une différence C vs C++, pour moi. C++ implicitement typedefs structs et unions à leurs balises; donc ajouter le typedef est superflu, mais pas une erreur. Je ne sais pas si cela fonctionne aussi pour les enums.

La chose à faire ensuite est de voir quelles définitions de variables sont autorisées après ces déclarations.

enum test etest;
test etest2;
struct named snamed;
named snamed2;
0
répondu luser droog 2011-06-19 06:01:30