问题 单个语句中的多个复合赋值:是否为未定义的行为?


我无法找到明确的答案:以下代码是否有未定义的行为?

int x = 2;
x+=x+=x+=2.5;

9445
2018-06-18 10:44


起源

这是 不 重复。这里的表达是 x+=(x+=10),这是不同的 (x+=10)+=10  - 这里的行为是未定义的,其他问题不是(在c ++ 11中)。 - interjay
我上面的评论提到了这个问题 在哪个版本的C ++标准中“(i + = 10)+ = 10”具有未定义的行为? 以前标记为重复。 - interjay
为什么你真的想知道? - Alex
亚历克斯,如果这个问题对我而言。我在面试时得到了类似的问题,我不确定它是否未定义。显然,没有人会在实际代码中使用此示例。 - makefun


答案:


行为未定义。让我们看一下稍微简单的表达式:

x += (x+=1)

在C ++ 11中,左边的值计算 x 相对于表达式的值计算,它是无序的 (x+=1)。这意味着价值计算 x 没有相对于任务的顺序 x (由于 x+=1),因此行为未定义。

这样做的原因是双方的价值计算 += 运算符相对于彼此未被排序(因为标准没有另外指定)。并且1.9p15州:

如果对标量对象的副作用相对于对同一标量对象的另一个副作用或使用相同标量对象的值进行的值计算未进行排序,则行为未定义。

在C ++ 03中,行为未定义,因为 x 在没有插入序列点的情况下被修改两次。


14
2018-06-18 10:58



注意:如果 x 是一个用户定义的对象 operator+=,然后它将被定义...... - Matthieu M.
对不起,先向下推特。正如您在对该问题的评论中所解释的那样,这两个表达方式是不同的,确实您的答案是完全正确的。 +1 - Johannes Schaub - litb


对于标准报价,请参阅其他答案。在这种情况下,它可能会找到两种不同的行为之一。

x += (x += 2);

可能是

x = 2 + 4 (= 6)

如果之前评估左侧x的值 x+=2 要么

x = 4 + 4 (= 8)

如果之后确定左操作符的x值。


-编辑-

我知道如果我说我不喜欢那些“任何可能发生的事情”的话,我就不会得到很多粉丝。 确实,无论我们在这里讨论的语句如何处理x的值,任何编译器都可以声明自己的标准符合。尽管如此,我认为这并不意味着operator + =可能会导致错误的结果,或者可能会忽略parantheses。 未定义的行为与任何其他情况下的未定义行为不同。

关于未定义行为的任​​何期望是不好的,但在上面的例子中,我看到了忽略任何可能结果但6和8的充分理由。

另外我实际上怀疑x在评估之后是8 int x=2; x += (x += 2); 对于大多数已建立的编译器(clang,g ++,vc,icpc ......)。

再说一遍,你不应该依赖这种行为,但这并不意味着它完全不可预测。


0
2018-06-18 11:08



至少 这里可能会出现两种行为。行为未定义,因此列举可能的行为是一项无穷无尽的任务。 - Pete Becker
表明存在至少两种不同的结果(通过矛盾显示)与枚举之间存在差异。对于案例2,这些是相同的。 - Alex
允许优化编译器 承担 您的程序的行为未定义。如果违反该假设,他们可以执行违反的转换 你的 假设。无论如何,它应该如何真正重要 x += (x += 2); 行为;无论它意味着什么,都有更明确的表达方式。 - Keith Thompson