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?
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.
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.
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