为了账号安全,请及时绑定邮箱和手机立即绑定

未定义的行为和序列点

未定义的行为和序列点

大话西游666 2019-05-20 16:51:30
什么是“序列点”?未定义的行为和序列点之间的关系是什么?我经常使用有趣和复杂的表达方式a[++i] = i;,让自己感觉更好。我为什么要停止使用它们?如果您已阅读此内容,请务必访问后续问题重新加载未定义的行为和序列点。
查看完整描述

4 回答

?
智慧大石

TA贡献1946条经验 获得超3个赞

这是我之前的答案的后续内容,包含C ++ 11相关资料。


先修课程:关系(数学)的基础知识。


在C ++ 11中没有序列点是真的吗?

是! 这是非常正确的。

序列点已被C ++ 11中的Sequenced BeforeSequenced After(以及UnsequencedIndeterminately Sequenced关系所取代。


究竟是什么'之前排序'的事情?

排序之前(§1.9/ 13)是一种关系,它是:

在由单个线程执行的评估之间并引发严格的部分顺序1

正式它意味着给定任意两个评价(见下文) AB,如果A之前测序 B,则执行A 应当先执行B。如果A之前没有进行测序BB之前没有进行测序A,然后AB未测序 2

评价AB不定测序或者当A前进行测序BB之前测序A,但它是未指定的,其3

[注释] 
1:严格偏序是一个二元关系 "<"在一组P其是asymmetric,和transitive的,即,对于所有的ab以及cP中,我们有:
........(I)。如果a <b则¬(b <a)(asymmetry); 
........(II)。如果a <b且b <c则a <c(transitivity)。
2:未经测试的评估的执行可能重叠
3:不确定顺序的评估不能重叠,但可以先执行。


在C ++ 11的上下文中,“评估”一词的含义是什么?

在C ++ 11中,表达式(或子表达式)的评估通常包括:

现在(§1.9/ 14)说:

一个完整的表达相关联的每个值的计算和副作用测序之前与相关联的每一个值的计算和副作用进行评估下一个完整表达

  • 琐碎的例子:

    int x; x = 10; ++x;

    在计算值和副作用之后,对与之相关++x的值计算和副作用进行排序x = 10;


因此,未定义行为与上述事物之间必然存在某种关系,对吧?

是! 对。

在(§1.9/ 15)中已经提到过

除非另有说明,否则对个体操作员的操作数和个别表达式的子表达式的评估是不确定的4

例如 :

int main(){
     int num = 19 ;
     num = (num << 3) + (num >> 3);}
  1. 对操作+员的操作数的评估相对于彼此是不确定的。

  2. 对操作数<<>>操作符的评估相对于彼此是不确定的。

4:在一个程序的执行过程中被评估一次以上的表达,未测序不定测序其子表达式的评估不需要在不同的评价一致的方式进行。

(§1.9/ 15)运算符操作数的值计算在运算符结果的值计算之前排序。

这意味着在x + y值计算之前,x并且y在计算值之前对其进行排序(x + y)

更重要的是

(§1.9/ 15)如果对标量物体的副作用相对于其中任何一个都没有排序

(a)对同一标量物体的另一个副作用

要么

(b)使用相同标量对象的值进行值计算。

行为未定义

例子:

int i = 5, v[10] = { };void  f(int,  int);
  1. i = i++ * ++i;  // Undefined Behaviour

  2. i = ++i + i++;  // Undefined Behaviour

  3. i = ++i + ++i;  // Undefined Behaviour

  4. i = v[i++];     // Undefined Behaviour

  5. i = v[++i]:     // Well-defined Behavior

  6. i = i++ + 1;    // Undefined Behaviour

  7. i = ++i + 1;    // Well-defined Behaviour

  8. ++++i;          // Well-defined Behaviour

  9. f(i = -1, i = -1); // Undefined Behaviour (see below)

当调用函数(函数是否为内联函数)时,与任何参数表达式相关联的每个值计算和副作用,或者使用指定被调用函数的后缀表达式,都会在执行每个表达式或语句之前对其进行排序。叫功能。[ 注意: 与不同参数表达式相关的值计算和副作用未被排序。- 结束说明 ]

表达式(5)(7)(8)不要调用未定义的行为。有关更详细的说明,请查看以下答案。


最后的说明

如果您发现帖子中有任何缺陷,请发表评论。高级用户(代表> 20000)请不要犹豫,编辑帖子以纠正拼写错误和其他错误。


查看完整回答
反对 回复 2019-05-20
?
慕桂英546537

TA贡献1848条经验 获得超10个赞

我猜这个改变有一个根本原因,让旧的解释更清晰,不仅仅是装饰性的:原因是并发性。未指定的细化顺序仅仅是选择几个可能的连续排序中的一个,这与排序之前和之后完全不同,因为如果没有指定的排序,则可以进行并发评估:旧规则不是这样。例如:

f (a,b)

先前要么是b,要么是b,然后是a。现在,可以使用交错的指令或甚至在不同的核上评估a和b。


查看完整回答
反对 回复 2019-05-20
?
PIPIONE

TA贡献1829条经验 获得超9个赞

C99(ISO/IEC 9899:TC3)这似乎从这个讨论迄今以下steteents是关于及其评价问题作了缺席。

[...]子表达式的评估顺序和副作用发生的顺序都是未指定的。(第6.5节第67页)

操作数的评估顺序未指定。如果尝试修改赋值运算符的结果或在下一个序列点之后访问它,则行为[sic]未定义。(第6.5.16节第91页)


查看完整回答
反对 回复 2019-05-20
  • 4 回答
  • 0 关注
  • 739 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信