操作员的评价顺序 *

Evaluation order of Operator *

我有以下代码:

int f(int &x, int c){
    c = c - 1;
    if (c == 0) return 1;
    x = x + 1;
    return f(x, c)*x;
}

现在,假设我这样调用上面的函数:

int p = 5;
std::cout << f(p, p) << std::endl;

的输出是9^4,因为x是引用传递的,所以x的最终值应该是9,但是当return的语句上面的函数改为:

return x*f(x, c);

输出是3024 (6*7*8*9)。为什么输出有差异?这与 Operator* 的评估顺序有什么关系吗?如果我们被要求预测上面这段代码的输出,它是固定的、编译器相关的还是未指定的?

当你写:

f(x,c)*x

编译器可以选择在调用 f 之前或之后检索 x 中存储的值(对于第二个操作数)。因此,有许多可能的执行方式。编译器不必在此选择中使用任何一致性。

为了避免这个问题你可以这样写:

auto x_temp = x;
return f(x, c) * x_temp;

注意:这是未指定的行为;不是未定义的行为,因为在任何函数调用之前和之后都有一个序列点(或者在 C++11 术语中,函数内的语句相对于调用代码是 indeterminately-sequenced,而不是未排序的)。

原因是 f() 函数对其 x 参数有副作用。当函数 returns.

时,传递给此参数的变量将增加第二个参数 c 的值

因此,当您交换操作数的顺序时,您会得到不同的结果,因为 x 在调用函数之前和之后包含不同的值。

但是,请注意,以这种方式编写的代码的行为是未定义的,因为编译器可以按任何顺序自由交换操作数的评估。因此它在不同的平台、编译器甚至不同的优化设置下可能表现不同。因此,通常有必要避免此类副作用。有关详细信息,请参阅 http://en.cppreference.com/w/c/language/eval_order