赋值子表达式的计算顺序

Order of evaluation of assignment subexpressions

本文关键字:计算 顺序 表达式 赋值      更新时间:2023-10-16

C++11标准(5.17,expr.ass)指出

在所有情况下,赋值都是在值计算之后排序的 的左右操作数,以及值计算之前 赋值表达式。关于 不确定序列的函数调用,复合的操作 作业是单一评估

这是否意味着,表达式:

int a = 1, b = 10;
int c = (a+=1) + (b+=1);
if ( c == 10+1+1+1 ) {
    printf("this is guaranteed");
} else {
    printf("not guaranteed"); 
}

将始终评估为c==23

表达式

int c = (a+=1) + (b+=1);

(编辑:添加了缺少的括号,我认为这就是您的意图)

具有以下子表达式

(1) a+=1
(2) b+=1
(3) (1)+(2)
(4) c = (3)

(1) 和 (2) 的计算顺序未指定,编译器可以自由选择它喜欢的任何顺序。

在编译器可以计算 (3) 之前,必须同时计算 (1) 和 (2)。

(3) 必须先求值,然后编译器才能求值 (4)。

现在,由于 (1) 和 (2) 的求值顺序无关紧要,总体结果已明确定义,您的代码将始终产生 13 并打印"现在是标准"。请注意,一直都是这样,这对 C++11 来说并不新鲜。

这一直是有保证的,并且在规则之前排序(或 C++11 之前)中的序列点规则不需要确定这一点。 在C++中,每个(子)表达式有两个重要的生成的代码中的影响:它有一个值(除非它是键入 void ),它可能有副作用。 已排序的之前/序列点规则影响副作用何时保证已经发生;它们对值没有影响的子表达式。 例如,在您的情况下,(a += 1)a赋值后将具有的值,无论实际分配何时发生。

在C++11中,a的实际修改保证采取修改前的地方 c ;在 C++11 之前,没有关于订单的保证。 但是,在这种情况下,有符合标准的程序不可能看到这种差异,所以它无所谓。 (这在像c = (c += 1)这样的情况下很重要,这将是 C++11 之前的未定义行为。

在您的示例中,编译器将发出错误,因为加法运算符的优先级高于赋值运算符的优先级。所以首先将计算 1 + b,然后尝试将 1 分配给表达式 (1 + b),但 (1 + b) 不是左值。