【问题标题】:Order of initialization for multiple declarators in a single declaration单个声明中多个声明符的初始化顺序
【发布时间】: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


【解决方案1】:

我不知道我是怎么错过的,考虑到我实际上是在整个文档中搜索“订单”这个词,但它确实存在

6.8C99语句和块

3 块允许将一组声明和语句组合成一个句法单元。 具有自动存储持续时间和可变长度的对象的初始化程序 具有块范围的普通标识符的数组声明符被评估并且值是 存储在对象中(包括将不确定的值存储在没有 initializer) 每次按执行顺序到达声明时,就好像它是一个 声明,并在每个声明中按照声明符出现的顺序

【讨论】:

  • 所以要完全清楚 int i = 0; int a = i++, b = i++; 被定义并保证总是产生 a == 0、b == 1 和 i == 2 ?
  • @2501:是的,没错。
  • 供参考,在K&R第2版中,A.9.3复合语句:“每次在顶部输入块时都会执行自动对象的初始化,并按照声明符的顺序进行"
【解决方案2】:

真的没有说明还是我错过了一些简单的东西?

订单未指定。这是因为,

 int a = i++, b = i++;

充当分隔符,而不是运算符。这里不保证初始化的顺序。

【讨论】:

  • 我认为你错了。除非另有明确说明,否则序列点按语法顺序应用。根据您的论点,您将无法说由; 分隔的副作用以特定顺序出现。顺便说一句,必须指定顺序,因为在b 的初始化器中,a 可以用作子表达式。
  • @JensGustedt; a 可以用作子表达式可能是因为未指定初始化顺序。可能存在编译器通过 a 的错误在 int a = i++, b = a + i++; 中未声明的情况
【解决方案3】:

原来如此。如果初始值假定为 0,则将分配给 a 值:1。 B 也将被赋值为 1,因为 i 的值没有改变。在这个阶段,a 和 b 的值被赋值。

您可以通过 printf 语句检查。 a= i++ 表示 a 的值为 i+1。

就像 b 也被赋予 i+1。

【讨论】:

  • 它将ab 设置为您的编译器或所有编译器中的特定值,并不意味着它是根据C 标准定义的。问题不在于 int a = i++, b = i++;ab 设置为什么值,而是它是否被定义(许多语法正确的 C 程序没有)。
  • 这实际上毫无意义。首先,在我的示例中,++ 是后增量。 a=i++ 不代表a 的值为i+1。我不知道你从哪里得到这个想法。后增量的结果是其操作数的旧值,而不是新值。其次,如上所述,语言规范明确要求每个声明后都有一个序列点。这意味着无论您如何对其进行切片,在我的示例中,都无法在 ab 中获得相同的值。如果你的编译器给你这样奇怪的结果,你的编译器就严重坏了。
  • 尝试在编译器中执行它:)
  • @Fahad Rana:我敢肯定每个人都尝试过多次在编译器中这样做。我从未见过的编译器的行为与您在答案中描述的一样。请您告诉我什么特定的编译器允许您观察到上述代码的极不寻常的结果?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2015-04-05
  • 1970-01-01
  • 2011-04-15
  • 2020-02-23
相关资源
最近更新 更多