Strange output, not as expected

2019-02-16 03:39发布

sorry for asking you a stupid question, but I just can't figure out why I keep on getting this output. So here is my code:

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

so what I expected to see in the first line of my output was the remainder and then the quotient that I get after calling the function getRemainderOf(). But instead when I cout the value of quotient like that I see that the value of quotient is a garbage value. So the value of the variable is not changed even though I've passed it to the function by using reference. The funny thing is that if I cout the remainder (got by calling the function) and the quotient separately I will get it right. I see that the problem might be in calling the function as a argument of the operator << function but I don't get it why the value of the quotient isn't changed since I call the function before I output it. This operator's associativity is left-to-right so what's wrong? So could you please tell me what is the reason of this output.

2条回答
Fickle 薄情
2楼-- · 2019-02-16 03:47

The order of evaluation of function arguments is unspecified. In these statements

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;

there are called overloaded operators << that are in fact functions. You have to split each statement in two statements. For example

cout << "("<< i*3 << "," << j*7 << ") "  <<( getRemainderOf(i*3, 7*j, quotient) ) ;
cout << " " << quotient <<endl;
查看更多
乱世女痞
3楼-- · 2019-02-16 03:54

What you've just found is a classic example of one of the quirks of C++. Your program can actually be decomposed into this simple example:

int i = 10;
f(i, ++i);

The compiler has the choice of function argument evaluation from left-to-right, but this is not guaranteed. Here's some standard text:

5.2/4 Postfix Epressions [expr.post]

When a function is called, each parameter shall be initialized with its corresponding argument. [Note: Such initializations are indeterminatly sequenced with respect to each other (1.9) - end note]

Because they are indeterminatly sequenced, the compiler has the freedom of evaluating ++i before the first argument and initializing it with the corresponding function parameter, and then evaluating i and initializing it with its respective parameter next.

The reason function call argument evaluation ambiguity is applicable here is because operator<<() is a function but it's just being called with the operator syntax. For example, this is what your code looks like if we use the operator-id syntax:

std::operator<<(std::operator<<(std::operator<<(std::cout, "(").operator<<(i*3), ",").operator<<(j*7), ")").operator<<(getRemainderOf(i*3, 7*j, quotient)).operator<<(quotient);

These are just chains of function calls with arguments and they obey the same rule as the one above.

The solution is to sequence the act of modifying the object and using it in the operator<<() call. You already achieved this with partitioning the operator<<() call into two statements with the semicolon ;, so the function is guaranteed to be called before quotient is printed.

查看更多
登录 后发表回答