C和C++中+ =的结果是什么?

Sve*_*nov 92 c c++

我有以下代码:

#include <stdio.h>
int main(int argc, char **argv) {
    int i = 0;
    (i+=10)+=10;
    printf("i = %d\n", i);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用gcc将其编译为C源代码,则会出现错误:

error: lvalue required as left operand of assignment
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用g ++将其编译为C++源代码,我将得到没有错误,当我运行可执行文件时:

i = 20
Run Code Online (Sandbox Code Playgroud)

为什么不同的行为?

das*_*ght 132

复合赋值运算符的语义在C和C++中是不同的:

C99标准,6.5.16,第3部分:

赋值运算符将值存储在左操作数指定的对象中.赋值表达式在赋值后具有左操作数的值,但不是左值.

在C++ 5.17.1中:

赋值运算符(=)和复合赋值运算符都是从右到左分组.所有都需要一个可修改的左值作为左操作数,并在赋值发生后返回左操作数的类型和值的左值.

编辑:(i+=10)+=10在C++ 98中,C++中的行为未定义,但在C++ 11中定义良好.请参阅NPE关于标准相关部分的问题的答案.

  • **重要**:注意`(i + = 10)+ = 10`是C++中未定义的行为,请参阅@aix answer. (7认同)
  • @dasblinkenlight:不,他的意思是*undefined*.在C++ 03及更早版本中,由于缺少插入序列点,修改表达式**的左值结果在所有编译器**中表现不可预测.如果它是*未指定*,它将表现出可预测但在不同的编译器上有所不同**. (4认同)
  • 它在像`int f(int&y)这样的设置中会很有用; f(x + = 10);` - 将对修改后的变量的引用传递给函数. (2认同)

NPE*_*NPE 51

除了无效的C代码之外,该行

(i+=10)+=10;
Run Code Online (Sandbox Code Playgroud)

会在C和C++ 03中导致未定义的行为,因为它会i在序列点之间修改两次.

至于为什么允许在C++中编译它:

[C++ N3242 5.17.1]赋值运算符(=)和复合赋值运算符从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.

同一段接着说

在所有情况下,分配的右侧和左侧的操作数的值计算后测序,并赋值表达式的值计算之前.

这表明在C++ 11中,表达式不再具有未定义的行为.

  • 这是不确定的行为是错误的.如果赋值在赋值表达式的值计算之前不是序列,那么`i = j + = 1`将导致不确定的值.从同一段引用"在所有情况下,赋值在右和左操作数的值计算之后,以及赋值表达式的值计算之前排序." 因此`(i + = 10)+ = 10`被明确定义为`i + = 10; i + = 10;`.另一方面,`(i + = 10)+ =(i + = 10)`是UB. (4认同)
  • 嗯,由于序列点,它肯定是UB.它也是*C中的无效代码*(但不是C++),但它与序列点无关,应该被编译器捕获. (3认同)
  • @KonradRudolph:不,编译器没有义务捕获未定义的行为,而不是形成错误的代码."应该被编译器捕获"部分是我们不同意的地方. (2认同)
  • C++ 11中不存在序列点,因此UB的实际原因是对"i"有两个未经序列的修改. (2认同)
  • 因为我看到有评论者之间在这一些分歧,我已将此作为一个单独的问题:http://stackoverflow.com/questions/10655290/in-c-does-i-10-10-result-在-未定义行为 (2认同)