【问题标题】:why i = ++i + 2 is undefined behavior? [duplicate]为什么 i = ++i + 2 是未定义的行为? [复制]
【发布时间】:2018-06-19 09:05:50
【问题描述】:

我已经阅读了一些关于评估顺序的内容,并且我了解一些由评估顺序引起的错误。

我的基本规则来自一个文本和例子:

  • 操作数计算的顺序独立于优先级和关联性。
  • 在大多数情况下,顺序基本上是未指定的。

所以对于这样的表达:int i = f1() * f2();

在进行乘法运算之前必须调用 f1 和 f2。毕竟,成倍增加的是他们的结果。但是,我们无法知道 f1 是否会在 f2 之前被调用,反之亦然。

未定义的行为示例:

int i = 0;
cout << i << " " << ++i << endl; 

我的理解:我将i++i 视为一个函数。我不知道哪个先评估,所以第一个 i 可能是 01 并且(规则)是有道理的。


while(beg != s.end())
    *beg = toupper(*beg++);  //Just another example.

我认为理解这一点的关键是将每个操作数视为一个“评估单元”,人们不知道这些单元中的评估顺序,但可以知道每个单元中的顺序

但是对于i = ++i + 2reference here,为什么会出错呢?我无法用我自己的结论来解释。

左边的i 用作左值不是指针++i 只是重写原始值,不改变存储地址。如果它先评估还是后评估会有什么问题?我的规则在这里失败了。

比较长,但尽量提供足够的背景信息,感谢您的耐心等待。


我不知道答案中经常提到的序列点。所以我想我需要先阅读一些有关它的内容。顺便说一句,辩论不是很有帮助,对于新手来说只是想知道为什么它被认为是错误的,就像在 C++11 之前一样?


我找到这个答案Undefined behavior and sequence points 很好地解释了为什么i = ++i + 2 在 C++11 之前是未定义的行为

【问题讨论】:

标签: c++ operator-precedence


【解决方案1】:

C++11 有新的排序规则。特别是,对于预增量 (++i),副作用(写入新值)在进一步使用新的增量值之前进行排序。由于赋值 i= 是在评估其右侧之后排序的,这意味着写入 ++i 是可传递排序的 - 在写入 i=(++i + 2) 之前

i=(i++ + 2) 则另当别论。对于后增量,副作用是sequence-after,这意味着两个分配不再相对于彼此排序。这是未定义的行为。

【讨论】:

    【解决方案2】:

    i = ++i + 2 中的两个“子函数”是= 运算符的显式赋值和++ 运算符的隐式赋值。

    preincrement 运算符被定义为返回变量的增量值,这肯定会用于加法(由+ 运算符执行)。然而,它没有被定义,什么时候增加的值应该被存储回i

    因此,不确定i 的最终值是old_i incremented plus 2 还是只是old_i incremented

    【讨论】:

    • "但是,它没有定义,当增加的值应该被存储回 i" 在 C++11 之前是但不是之后。
    • @CiaPan - 唉,你和我在这方面是不正确的。 (我已经删除了我的答案)。将 +1 转换为 -1 的简单编辑。
    • 没有“未定义值是 X 还是 Y”这样的东西。如果该值可能是 X 或 Y,那么这种情况称为 未指定行为,但事实并非如此。 未定义的行为 意味着任何事情都可能发生。你也用过去时说话,但你没有指定行为何时从未定义变为已定义。
    • @M.M 我之前的至少三个答案和 cmets 描述了 when 发生了变化,所以我不需要再次指定。我的目标是显示“未定义”状态的来源。
    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    相关资源
    最近更新 更多