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


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

为什么会有不同的行为?


85
不同的语言,不同的语法规则?就个人而言,我会在代码审查中拒绝该代码。
Max

7
避免使用此类imo代码...每个人都不知道。
Allaire 2012年

1
毫无疑问,代码不是干净的,应避免在“实际”开发中使用。但是,尽管如此,我仍然观察到相同的行为,并想知道其原因。
ulidtko

9
这不是真实软件的代码摘录。这只是我偶然发现的一个纽结。
Svetlin Mladenov

3
@JohnDibling我认为投票表决特别是(i + = 10)+ = 10我不知道哪种语言是合法代码,而且他说C ++实际上可以编译它的事实引起了我的兴趣。
Tony318

Answers:


133

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

C99标准6.5.16,第3部分:

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

在C ++ 5.17.1中:

赋值运算符(=)和复合赋值运算符均从右到左分组。全部都需要可修改的左值作为其左操作数,并在分配发生后返回具有左操作数的类型和值的左值。

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


正确。一个返回结果值,一个返回变量(地址)
texasbruce 2012年

7
重要提示:请注意,这(i+=10)+=10是C ++中的未定义行为,请参阅@aix答案。
大卫·罗德里格斯(DavidRodríguez)-dribeas,2012年

@DavidRodríguez-dribeas您的意思是未指定未定义,对吗?
dasblinkenlight 2012年

4
@dasblinkenlight:不,他的意思是undefined。在C ++ 03和更早版本中,由于缺少中间的序列点,因此在所有编译器中修改表达式的左值结果的行为都是无法预测的。如果未指定,则在不同的编译器上它的行为可预测但有所不同
贾斯汀ᚅᚔᚈᚄᚒᚔ2012年

2
在诸如int f(int &y); f(x += 10);-将对修改后的变量的引用传递到函数中之类的设置中,这将很有用。
Phil Miller 2012年

51

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

(i+=10)+=10;

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

关于为什么允许在C ++中进行编译:

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

同一段继续说

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

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


3
好吧,肯定是UB,因为有序列点。它也是C语言中的无效代码(但不是C ++),但与序列点无关,应该由编译器捕获。
康拉德·鲁道夫

2
@KonradRudolph:不,与格式错误的代码相反,编译器没有义务捕获未定义的行为。我们不同意“应该被编译器捕获”的部分。

2
序列点在C ++ 11中不存在,因此UB的实际原因是有两个未排序的修改i
Mankarse 2012年

4
这是未定义的行为是错误的。如果在赋值表达式的值计算之前赋值不是顺序的,i = j+=1则将导致不确定的值。在同一段中,您引用了“在所有情况下,赋值在左右操作数的值计算之后,在赋值表达式的值计算之前进行排序。” 因此(i+=10)+=10是很好的定义i += 10; i += 10;。另一方面(i+=10)+=(i+=10)是UB。
bames53 2012年

2
:因为我看到有评论者之间在这一些分歧,我已将此作为一个单独的问题stackoverflow.com/questions/10655290/...
NPE
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.