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