93

我有以下代码:

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

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

error: lvalue required as left operand of assignment

但是,如果我使用 g++ 将其编译为 C++ 源代码,则不会出现错误,并且当我运行可执行文件时:

i = 20

为什么会有不同的行为?

4

2 回答 2

134

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

C99 标准,6.5.16,第 3 部分:

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

在 C++ 5.17.1 中:

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

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

于 2012-05-18T13:57:58.457 回答
51

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

(i+=10)+=10;

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

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

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

同一段继续说

在所有情况下,赋值都在左右操作数的值计算之后和赋值表达式的值计算之前进行排序。

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

于 2012-05-18T13:56:06.507 回答