方案1:
#include <iostream>
using namespace std;
int a = 5;
int fun1() {
a = 17;
return 3;
}
int main() {
// Even though C languages are left associative,
// this line of code evaluates fun1() first:
a = a + fun1();
//a = 17 + 3
printf("%d", a);
a = fun1() + a;
printf("\n%d", a);
return 0;
}
输出:
20
20
方案2:
int a = 10;
int fun() {
a = 15;
return 30;
}
int main(void) {
// Whereas in this example, fun() is evaluated last:
int x = a + 10 + fun();
//x = 10 + 10 + 30
a = 10;
int y = fun() + 10 + a;
printf(" x = %d \n y = %d \n", x, y);
return 0;
}
输出:
x = 50
y = 55
为什么程序 1 首先计算 fun1(),而在程序 2 中,当 fun() 放在表达式末尾时最后才计算?
据我了解,基于 C 的语言是左关联的,那么为什么程序 1 的行为很奇怪?
从历史上看,函数调用的参数求值顺序是未指定的。这意味着对于通话
foo(bar(), baz());
编译器是否需要调用
bar()
,而不是 baz()
,或者反之亦然。请记住,调用运算符是通用函数调用的另一种情况,即 baz() + bar()
在语义上与 operator+(baz(), bar())
相同。
出于实际目的,编译器过去常常从最后到第一个计算参数,因为这是许多函数调用 ABI 将参数推入堆栈的顺序。
你混合了两个概念(虽然这种情况经常发生),让我们看看表达:
a = b + c + d * e;
运算符优先级和结合性意味着该表达式等于
a = ( ( b + c ) + ( d * e ) );
但这并不意味着例如,
d * e
必须在b + c
之前评估,只是因为*具有更高的优先级。详细信息可以在这里找到评估顺序
除非下面指出,C++ 中没有从左到右或从右到左求值的概念。不要与运算符的从左到右和从右到左结合性相混淆:表达式 f1() + f2() + f3() 被解析为 (f1() + f2()) + f3( )由于运算符+的从左到右关联性,但是对 f3 的函数调用可以在运行时首先、最后或在 f1() 或 f2() 之间进行计算。
重点是我的。
三个独立的概念经常被混淆:
求值顺序,决定了操作数的求值顺序。
标准中通常未指定这一点。
优先级,它确定两个运算符中的哪一个首先被评估。
例如,在
a + b * c
中,乘法先于加法计算。关联性,它决定首先评估哪个运算符具有相同的优先级。
例如,
<<
是左结合的; a << b << c
被评估为 (a << b) << c
,而赋值是右关联的; a = b = c
是a = (b = c)
。该类型的评估顺序在标准中没有规定。由编译器来进行它正在做的优化。