未定义的行为和序列点

时间:2010-11-14 05:37:46

标签: c++ undefined-behavior c++-faq sequence-points

什么是“序列点”?

未定义行为和序列点之间的关系是什么?

我经常使用像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的想法,所以你的答案很可能会被那些提出想法的人阅读。)

5 个答案:

答案 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)