为什么我= ++我调用未定义的行为?

这个问题在这里已经有了答案:

  • 为什么这些构造(使用++)在C中的未定义行为? 13个答案

  • 你错过了一些未定义的行为。 未定义的行为只是意味着编译器可以做任何想做的事情。 它可以抛出一个错误,它可以(如GCC所示)显示一个警告,它可以导致恶魔飞出你的鼻子。 最主要的是,它不会表现良好,编译器之间的行为也不一致,所以不要这样做!

    在这种情况下,编译器不必在返回语句的rhs之前让操作符的lhs的副作用完成。 这对你来说似乎很有趣,但你不会像电脑那样思考。 如果需要,它可以计算返回值并将其返回到寄存器中,将其分配给i,然后对实际值执行增量。 所以它看起来更像

    register=i+1;
    i=register;
    i=i+1;
    

    该标准不能保证这不会发生,所以不要这样做!


    未定义的行为出现是因为变量i在两个序列点之间不止一次被修改。 序列点是之前的评估的所有副作用都可见的点,但未见副作用。 该标准规定:

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

    那么,我们担心的副作用是什么?

  • ++i ,它给i赋值i+1
  • i = ++i ,它给我i表达式++i的值,即i+1
  • 所以,我们会得到两个(不可否认的,等价的)副作用:将i+1分配给变量i 。 我们关心的是,在这两个序列点之间会发生这些副作用?

    什么操作构成序列点? 有多个,但这里只有一个实际相关:

  • 在完整表达式的末尾(在这种情况下, i = ++i是一个完整的表达式)
  • 即,预增量++i 不是序列点 。 这意味着两个副作用(增量和分配)将发生在相同的两个序列点之间,修改相同的变量i 。 因此,这是不确定的行为; 两个修改碰巧具有相同的值的事实是无关紧要的。


    但为什么在序列点之间多次修改一个变量是不好的? 为了防止这样的事情:

    i = ++i + 1;
    

    这里, i是递增的,但是由于预增量的语义,它也被分配了值(i+1) + 1 。 由于副作用具有模糊的顺序,因此行为未定义。

    现在,假设在标准中有一个特殊情况,只要值相同,两个序列点之间的多个修改就可以,但这可能会使编译器实现无用地复杂化,而没有太多好处。

    链接地址: http://www.djcxy.com/p/73275.html

    上一篇: Why does i = ++i invoke undefined behaviour?

    下一篇: sequence points in c