奇怪的输出,不是预期的

Strange output, not as expected

本文关键字:输出      更新时间:2023-10-16

很抱歉问你一个愚蠢的问题,但我就是不明白为什么我一直得到这个输出。下面是我的代码:

#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;