运营商的评估顺序*

时间:2017-02-07 04:55:30

标签: c++ reference operator-precedence

我有以下代码:

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*的评估顺序有什么关系吗?如果我们被要求预测上面一段代码的输出,它是固定的,编译器相关的还是未指定的?

2 个答案:

答案 0 :(得分:2)

当你写:

f(x,c)*x

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

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

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

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

答案 1 :(得分:1)

原因是f()函数对其x参数有副作用。当函数返回时,传递给此参数的变量将增加第二个参数c的值。

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

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