C89中用逗号分隔的声明符序列

编程语言 2026-07-09

C89标准对带初始化的逗号分隔声明序列中表达式的求值顺序有何规定?我在“Declarations(声明)”部分、也在“Initialization(初始化)”和“Program execution(程序执行)”中都没找到答案。我只发现初始化表达式末尾存在序列点(附录C)。例如:

int t = 1;
void block (void)
{
    int a = (t *= 2), b = (t *= 3);
    /* Is it guaranteed that a==2 and b==6 ? */
}

更新:

又有一个 答案 针对类似的问题。

解决方案

在你所说的代码块中:

Is it guaranteed that a==2 and b==6

是的,这是可以保证的。

[C89] 的第3.6节指出如下:

A full expression is an expression that is not part of another expression. Each of the following is a full expression: an initializer; the expression in an expression statement; the controlling expression of a selection statement ( if or switch ); the controlling expression of a while or do statement; each of the three expressions of a for statement; the expression in a return statement. The end of a full expression is a sequence point.

关于序列点的附录A.2列出了以下内容:

The end of a full expression: an initializer (3.5.7);

这意味着在C89下,a 的初始化与 b 的初始化之间存在一个序列点。

在C99和 C11中,措辞发生了变化。特别是关于声明符(即对象及其初始化的声明)的C11第 6.7.6p3节指出:

A full declarator is a declarator that is not part of another declarator. The end of a full declarator is a sequence point.

关于序列点的附录C 列出:

The end of a full declarator: declarators

因此这一点同样一直延续到C11。

在C17中确实有变更,具体地说,上述6.7.6p3中用粗体标出的段落以及上文提到的附录C 中的那一行都被移除了。鉴于这一版相对较小,如附录M.1所述:

There are no major changes in this edition (__STDC_VERSION__201710L), only technical corrections and clarifications.

这似乎表明这并非功能性变更。事实上,如果我们再看C11/C17的 6.8p3(以及C23中几乎相同的表述:

The initializers of objects that have automatic storage duration, and the variable length array declarators of ordinary identifiers with block scope, are evaluated and the values are stored in the objects (including storing an indeterminate value in objects without an initializer) each time the declaration is reached in the order of execution, as if it were a statement, and within each declaration in the order that declarators appear.

以上明确表示,在下面的声明

int a = (t *= 2), b = (t *= 3);

实际上在 a 的初始化与 b 的初始化之间存在一个序列点。


请注意,C11的 6.7.9p23 / C23的 6.7.10p24的以下段落并不适用:

The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified

因为这仅适用于聚合类型,参见C11 6.7.9p12 / C23 6.7.10p13:

The rest of this subclause deals with initializers for objects that have aggregate or union type.

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章