很抱歉问你一个愚蠢的问题,但我就是不明白为什么我一直得到这个输出。下面是我的代码:
#include <cstdio>
#include <iostream>
using namespace std;
unsigned n = 4242;
int getRemainderOf(int m, int n, int& quotient);
static int l = 0;
int main()
{
int quotient; // the value of which should be changed after calling the func.
for(int i=-1; i<=1; ++i)
{
for(int j=-1; j<=1; ++j)
{
if( i && j )
{
cout << "("<< i*3 << "," << j*7 << ") " <<( getRemainderOf(i*3, 7*j, quotient) ) << " " << quotient <<endl;
cout << "("<< i*7 << "," << j*3 << ") " << getRemainderOf(i*7, 3*j, quotient) << " "; cout << quotient <<endl;
}
}
}
return 0;
}
int getRemainderOf(int m, int n, int& quotient)
{
++l;
cout << l <<endl;
quotient = m / n;
cout << " quotient " << quotient <<endl;
return m % n;
}
所以我期望在输出的第一行中看到的是余数,然后是调用函数getRemainderOf()后得到的商。但是当我像这样计算商的值时,我发现商的值是一个垃圾值。所以变量的值没有改变,即使我通过引用把它传递给函数。有趣的是,如果我分别计算余数(通过调用函数得到)和商,我就会得到正确的结果。我看到问题可能是在调用函数作为操作符<<函数,但我不明白为什么商的值没有改变,因为我在输出它之前调用了函数。这个运算符的结合律是从左到右的,有什么问题吗?所以你能告诉我这个输出是什么原因吗?
您刚才发现的是c++的一个典型的怪癖。您的程序实际上可以分解成这个简单的示例:
int i = 10;
f(i, ++i);
编译器可以选择从左到右的函数实参求值,但这不能保证。下面是一些标准文本:
5.2/4后缀有[expr.post]
调用函数时,每个形参都要用对应的实参初始化。[注意:这些初始化是相对于彼此的不确定排序的(1.9)- 结束注意]
由于它们是不确定顺序的,编译器可以自由地在第一个参数前求++i
并使用相应的函数参数初始化,然后再求i
并使用相应的参数初始化。
函数调用参数评估歧义在这里适用的原因是因为operator<<()
是一个函数,但它只是用操作符语法调用。例如,如果我们使用operator-id语法,您的代码看起来是这样的:
std::operator<<(std::operator<<(std::operator<<(std::cout, "(").operator<<(i*3), ",").operator<<(j*7), ")").operator<<(getRemainderOf(i*3, 7*j, quotient)).operator<<(quotient);
这些只是带参数的函数调用链,它们遵循与上面相同的规则。
解决方案是将修改对象的行为排序并在operator<<()
调用中使用它。通过使用分号;
将operator<<()
调用划分为两个语句,您已经实现了这一点,因此可以保证在打印quotient
之前调用该函数。
函数参数的求值顺序未指定。在这些语句中
cout << "("<< i*3 << "," << j*7 << ") " <<( getRemainderOf(i*3, 7*j, quotient) ) << " " << quotient <<endl;
cout << "("<< i*7 << "," << j*3 << ") " << getRemainderOf(i*7, 3*j, quotient) << " "; cout << quotient <<endl;
有重载操作符<<它们实际上是函数。你必须把每个语句分成两个语句。例如
cout << "("<< i*3 << "," << j*7 << ") " <<( getRemainderOf(i*3, 7*j, quotient) ) ;
cout << " " << quotient <<endl;