【发布时间】:2015-01-11 21:42:25
【问题描述】:
刚刚浏览了 C99 和 C11,试图弄清楚它们是否保证单个声明中的多个声明符从左到右按顺序执行。他们确实说每个完整的声明符都以一个序列点结束
6.7.5C99声明符
6.7.6C11声明符
3 完整的声明符是不属于另一个声明符的声明符。完整声明符的结尾是一个序列点。[...]
但似乎没有什么可以说各个初始化是按从左到右的顺序执行的。是真的没有说明还是我遗漏了一些简单的东西?
int main() {
int i = 0;
int a = i++, b = i++;
// Are values of `a` and `b` specified here?
}
如果未指定顺序,则以下实现模式为非法
int array[N];
for (int *element = array, *element_end = element + N;
element != element_end;
++element)
*element = 0;
这让我感到相当惊讶。 (我确实意识到我可以用array + N 来初始化element_end。)
附: C++ 规范在这方面也不是完全明确的。它有一个脚注说T d1, d2; 等同于T d1; T d2;,但这些都是非规范的。因此显然DR#1342
【问题讨论】:
-
可能相关(我目前不完全理解那句话):C99 (n1256) 6.7.8 p23 未指定初始化列表表达式中任何副作用发生的顺序。( 133) 和 C11 (n1570) 6.7.9 p23 初始化列表表达式的计算相对于彼此的顺序是不确定的,因此未指定任何副作用发生的顺序。(152);脚注为特别是,评估顺序不必与子对象初始化的顺序相同。对于两个草稿。
-
@mafso:我看到了这些声明,但它们遵循 6.7.8/12 (C99),其中说“本子条款的其余部分处理具有聚合或联合类型的对象的初始化程序。”。这些语句是关于单个聚合初始值设定项中的各个初始值设定项。这是一个完全不同的故事。
-
@mafso, initialization list 包含初始化化合物所需的子部分,例如
struct或数组。我们在这里看到的是独立的声明器,每个声明器都有一个初始化器。 -
@JensGustedt,序列点对我来说似乎还不够。
f() + g()在每个函数调用之后也有一个序列点(就像一个完整的声明器在其末尾一样)。虽然代码显然不是 UB,但我不确定a是否可能是 1 而b是 0 这里。 -
@mafso,微妙之处在于“如果未另行指定”。对于指定的表达式,6.5 p3:除后面指定的外,子表达式的副作用和值计算是无序的。
标签: c