什么是“序列点”?
未定义行为和序列点之间的关系是什么?
我经常使用像a[++i] = i;
这样有趣且复杂的表达方式来让自己感觉更好。我为什么要停止使用它们?
如果您已阅读此内容,请务必访问后续问题 Undefined behavior and sequence points reloaded 。
<子> (注意:这是Stack Overflow's C++ FAQ的一个条目。如果您想批评在此表单中提供常见问题解答的想法,那么the posting on meta that started all this就是这样做的地方。在C++ chatroom中监控了这个问题,首先是FAQ的想法,所以你的答案很可能会被那些提出想法的人阅读。) 子>
答案 0 :(得分:656)
答案 1 :(得分:270)
答案 2 :(得分:23)
C ++ 17 (N4659
)包含提案Refining Expression Evaluation Order for Idiomatic C++
它定义了更严格的表达式评估顺序。
特别添加 以下句子 :
8.18分配和复合赋值运算符:
....在所有情况下,分配都在值之后排序 计算右和左操作数,并在赋值表达式的值计算之前。 右操作数在左操作数之前排序。
它使以前未定义的行为的几个案例有效,包括有问题的行为:
a[++i] = i;
然而,其他几个类似案例仍会导致未定义的行为。
在N4140
:
i = i++ + 1; // the behavior is undefined
但在N4659
i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined
当然,使用符合C ++ 17的编译器并不一定意味着应该开始编写这样的表达式。
答案 3 :(得分:11)
我猜这个改变有一个根本原因,让旧的解释更清晰不仅仅是装饰性的:这个原因是并发性的。未指定的细化顺序仅仅是选择几个可能的连续排序中的一个,这与排序之前和之后完全不同,因为如果没有指定的排序,则可以进行并发评估:旧规则不是这样。例如:
f (a,b)
先前要么是b,要么是b,然后是a。现在,可以使用交错的指令或甚至在不同的核上评估a和b。
答案 4 :(得分:0)
在C99(ISO/IEC 9899:TC3)
中,到目前为止似乎没有进行此讨论,以下是关于评估顺序的内容。
[...]子表达式的求值顺序以及其中的顺序 副作用均未明确说明。 (第6.5页,第67页)
操作数的评估顺序未指定。如果尝试 用于修改赋值运算符的结果或对其进行访问 在下一个序列点之后,行为[sic]未定义。(部分 6.5.16 pp 91)