Home > Blockchain >  Why is "static;" valid C syntax?
Why is "static;" valid C syntax?

Time:12-09

I am looking at the C11 Standard PDF (Page 463), and I am confused about the lexical grammar of declarations. It seems like code like this one seems to be grammatically valid in C11:

static;
static const int;
long int const typedef long;

even though there does not seem to be any use for such a declaration.


To be specific, it's this part here which confuses me:

declaration: 
  declaration-specifiers init-declarator-list<opt> ;

declaration-specifiers:
  storage-class-specifier declaration-specifiers<opt>
  type-specifier declaration-specifiers<opt>
  type-qualifier declaration-specifiers<opt>
  function-specifier declaration-specifiers<opt>
  alignment-specifier declaration-specifiers<opt>

It seems like init-declarator-list in a declaration has been made explicitly optional. Is there any use for declarations without it?

CodePudding user response:

(That is not the C standard; it is an unofficial draft. And page 463 is non-normative text—it is just informative and not a binding part of the standard. This answer uses the official C 2018 standard, which has only technical corrections and clarifications from the 2011 standard.)

Speaking only to the formal grammar in the C standard, a declaration production, shown in C 2018 6.7 1, may be declaration-specifiers init-declarator-listopt ;. In that, declaration-specifiers may produce storage-class-specifier declaration-specifiersopt, and init-declarator-list may be absent, giving storage-class-specifier declaration-specifiersopt ;. Then the latter declaration-specifiers may be absent, giving storage-class-specifier ;, which finally can produce static ;.

However, the rules of the C standard go beyond the grammar. C 2018 6.7 2 says:

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.

The declaration static ; does not declare a declarator, a tag, or any member of an enumeration, so it violates this constraint. Then a conforming C implementation must issue a diagnostic message for it, although it may nonetheless accept it.

static const int ; and long int const typedef long ; also violate this constraint.

Further, C 2018 6.7.2 2 says:

At least one type specifier shall be given in the declaration specifiers in each declaration,…

Since static ; has no type specifier, such as void, int, or long double _Complex, it violates this constraint as well.

static const int ; and long int const typedef long ; do not violate this constraint.

It seems like init-declarator-list in a declaration has been made explicitly optional. Is there any use for declarations without it?

Yes, we can usefully declare structure, union, and enumeration tags, as in struct foo { int x; };. This declares the type struct foo and has no init-declarator (at the main level; there is one nested inside, of course).

We can also declare enumeration constants, as in struct foo { apple, banana };. This has no init-declarator at any level.

The fact that there are useful declarations with no init-declarator meant that either init-declarator had to be kept optional in the production or the production had to be split into two productions, one of which allowed declaring structures and such with no init-declarator and one of which produced declarations with a mandatory init-declarator. Presumably the nuisance of complicating the grammar presentation was not considered worth the benefit of reducing the semantic constraints.

  • Related