评估顺序:C

时间:2018-05-30 15:16:51

标签: c undefined-behavior operator-precedence

围绕C语句x = b[i] + i++;及其定义进行了讨论。

所述陈述未定义的论点如下:

C99的第6.5段规定:

  

[...]子表达式的评估顺序和副作用发生的顺序都是未指定的。

因此,不能保证i在下标运算符中用作数组的索引后递增。

但是,我对说法的解释不同。

C99的第6.5节还指出:

  

在上一个和下一个序列点之间,对象应具有其存储值   通过表达式的评估最多修改一次。此外,先前的价值   应该只读以确定要存储的值。

C99的第5.1.2.3段规定:

  

目前   执行序列中的某些指定点称为序列点,所有副作用   以前的评估应是完整的,没有后续评估的副作用   应该发生。

序列点列表在附录C中给出,只有以下内容与有问题的陈述相匹配。

  

完整表达式的结束

b[i]i的元素b的价值)和i++的元素{仅i)的评估可以按任意顺序进行完成(和=的评估,即RHS的值)。但是,整个陈述的副作用推迟到所有这些评估之后,因为这是唯一的序列点。在这种情况下,副作用是x的变化和i的增量。

谁是对的?是否有其他段落与论点相关?在C ++中有什么不同吗?

3 个答案:

答案 0 :(得分:2)

副作用 不会延迟到序列点 - 它们可以在评估后立即应用。或不。

C 2011有一些略有不同(更精确)的语言:

如果相对于不同的副作用,对标量对象的副作用是无效的 在相同的标量对象上或使用相同标量的值进行值计算 对象,行为未定义。

C 2011, §6.5 ¶2

i++i有副作用,b[i]在值计算中使用i,而两个子表达式未排序相对于彼此(即没有中间序列点)。因此,b[i] + i++的行为未定义。

答案 1 :(得分:2)

您对第6.5节的引用是相关的:

  

在前一个和下一个序列点之间,一个对象应该具有它   通过表达式的评估,最多修改一次存储值。   [在那种情况下,f]此外,先前的值   应在[在这些序列点之间]读取,以确定该值   存储。

(澄清我的。)

在您的陈述中,i的值都被修改并用作b的索引。您的语句不包含内部序列点,因此这些效果必须在同一对序列点之间发生。因此该声明违反了引用的要求。然后适用第4节第2段:

  

如果''''或'''''''要求出现在a。之外   违反了约束,行为未定义。 [...]

这就是它的全部。无需其他考虑因素。关于实际操作顺序的论证完全不相关。

尽管如此,你声称

  

整个陈述的副作用推迟到最后   这些评估是因为这是唯一的序列点。

反映了对序列点的严重误解。 事件发生时,序列点不代表的时间,而是事件发生之间的边界。副作用不仅不会延迟到下一个序列点,它们(通过标准)的约束远远少于计算表达式值所涉及的操作。

答案 2 :(得分:1)

§6.5.2.4陈述

  

更新操作数存储值的副作用应发生在前一个和下一个序列点之间。

就像尤金的评论所说的那样。如果对于第6.5(1)段中的问题中引用的陈述不够清楚

  

先前的值应该是只读的,以确定要存储的值。

也会被直接侵犯。 i的值不只是读取以确定递增后的值,还作为下标运算符的操作数。

questionits accepted answer可能会提供更多见解,因为它讨论了,运算符引入的序列点及其与潜在的UB激发分配行为的相互作用。