为什么 "static;" 有效的 C 语法?

Why is "static;" valid C syntax?

我在看C11 Standard PDF (第463页),我对声明的词法语法感到困惑。看起来像这样的代码在 C11 中似乎在语法上是有效的:

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

尽管这样的声明似乎没有任何用处。


具体来说,让我困惑的是这里的这一部分:

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>

声明中的 init-declarator-list 似乎已明确设为可选。没有它声明还有用吗?

(这不是 C 标准;它是一个非官方草案。第 463 页是非规范性文本——它只是提供信息而不是标准的约束部分。这个答案使用官方 C 2018 标准,其中只有 2011 年标准的技术更正和说明。)

仅针对C标准中的形式语法,C 2018 6.7 1中显示的declaration产生式可能是declaration-specifiers init-declarator-listopt ;。在那里,declaration-specifiers 可能会产生 storage-class-specifier declaration-specifiers optinit-declarator-list 可能不存在,给出 storage-class-specifier 声明说明符opt ;。那么后面的declaration-specifiers可能就没有了,给出storage-class-specifier;,最终可以产生static ;.

但是,C 标准的规则超出了语法范围。 C 2018 6.7 2 说:

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.

声明 static ; 没有声明声明符、标记或枚举的任何成员,因此它违反了此约束。然后一个符合标准的 C 实现必须为它发出一个诊断消息,尽管它仍然可以接受它。

staticconstint;longintconsttypedeflong ;也违反了这个约束。

此外,C 2018 6.7.2 2 说:

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

由于 static ; 没有类型说明符,例如 voidintlong double _Complex,它也违反了此约束。

staticconstint;longintconsttypedeflong ;不要违反这个约束。

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

是的,我们可以有用地声明结构、联合和枚举标记,如 struct foo { int x; }; 中所示。这声明了类型 struct foo 并且没有 init-declarator(在主层;当然有一个嵌套在里面)。

我们也可以声明枚举常量,如struct foo { apple, banana };。这在任何级别都没有 init-declarator

事实上有一些有用的声明没有 init-declarator 意味着 init-declarator 必须在生产或生产必须分成两个生产,其中一个允许声明结构等没有 init-declarator 并且其中一个产生带有强制性 init 的声明-声明符。据推测,使语法表示复杂化的麻烦不值得减少语义约束的好处。