Legality of `typedef struct foo {int bar};`

2019-06-19 05:13发布

问题:

This question arises from the question Is a struct {...}; a type or an unnamed variable?

In that question, the OP asked about

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

I am asking about the legality of the above. Is a diagnostic required when code containing the above is compiled (or to make it simpler, typedef struct foo {int bar;};)?

My take is that it is legal, that a diagnostic is not required from a language lawyer perspective. (Aside: I am not advocating using this. It is very worthy of a diagnostic. I would very much want the compiler to warn me if I mistakenly wrote code like the above.)


Section 6.7 of the C11 standard dictates the syntax of a declaration: declaration-specifiers init-declarator-listopt ; Note that the init-declarator-list is optional. This might lead one to think that typedef int; is valid. It isn't because the standard also says that

A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.

Thus typedef int; and typedef struct {int bar}; are illegal because they do not declare a declarator, a tag, or a member of an enumeration.

On the other hand, it appears to me that typedef struct foo {int bar;}; is legal because it does declare something. In particular, it declares and defines the struct tag foo.

Is the above reasoning correct?

回答1:

6.7.1 Storage class specifiers defines typedef as a storage class specifier with the following comment : The typedef specifier is called a ‘‘storage-class specifier’’ for syntactic convenience only;

And 6.7 Declaration contains:

Syntax:

  • declaration:
    • declaration-specifiers init-declarator-listopt
  • declaration-specifiers:
    • storage-class-specifier declaration-specifiersopt
    • type-specifier declaration-specifiersopt
    • type-qualifier declaration-specifiersopt
    • function-specifier declaration-specifiersopt
  • init-declarator-list:
    • init-declarator
    • init-declarator-list , init-declarator
  • init-declarator:
    • declarator
    • declarator = initializer

First constraint is : A declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration

As the init-declarator-list is optional in a declaration, provided a declarator or tag is declared, I would say that typedef struct foo {int bar;}; is a declaration decomposed as storage-class-specifier type-specifier with no init-declarator. But as the type-specifier declares internally a tag (foo) the constraint is respected.

My conclusion is that such a construct is valid and only produces warning on compilers.



回答2:

In the quote you cited there is written that a declaration shall declare among other things a tag.

So this declaration

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

simply declares struct student_s and equivalent to declaration without the typedef specifier

struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

It does does not introduce a typedef name in the scope.



回答3:

this typedef:

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;
};

yields the following:

warning useless storage class specifier in empty declaration [enabled by default]

So the syntax is acceptable, but without a declarer, the code is trash