围绕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 ++中有什么不同吗?
答案 0 :(得分:2)
副作用 不会延迟到序列点 - 它们可以在评估后立即应用。或不。
C 2011有一些略有不同(更精确)的语言:
如果相对于不同的副作用,对标量对象的副作用是无效的 在相同的标量对象上或使用相同标量的值进行值计算 对象,行为未定义。
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
的值不只是读取以确定递增后的值,还作为下标运算符的操作数。
此question和its accepted answer可能会提供更多见解,因为它讨论了,
运算符引入的序列点及其与潜在的UB激发分配行为的相互作用。