Strangely enough (or perhaps not so strangely...) it looks to me like gcc is correct to accept this.
If this was declared static
instead of extern
, then it would have internal linkage, and §6.9.2/3 would apply:
If the declaration of an identifier for an object is a tentative definition and has internal
linkage, the declared type shall not be an incomplete type.
If it didn't specify any storage class (extern
, in this case), then §6.7/7 would apply:
If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator, or by the end of its init-declarator if it has an
initializer; in the case of function arguments (including in prototypes), it is the adjusted type (see 6.7.5.3) that is required to be complete.
I either of these cases, void
would not work, because (§6.2.5/19):
The void type [...] is an incomplete type that cannot be completed.
None of those applies, however. That seems to leave only the requirements of §6.7.2/2, which seems to allow a declaration of a name with type void
:
At least one type specifier shall be given in the declaration specifiers in each declaration,
and in the specifier-qualifier list in each struct declaration and type name. Each list of
type specifiers shall be one of the following sets (delimited by commas, when there is
more than one set on a line); the type specifiers may occur in any order, possibly
intermixed with the other declaration specifiers.
[ ... more types elided]
I'm not sure that's really intentional -- I suspect the void
is really intended for things like derived types (e.g., pointer to void) or the return type from a function, but I can't find anything that directly specifies that restriction.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…