views:

602

answers:

3

I know cout and printf have buffer today, and it is said that the buffer is some like a stack and get the output of cout and printf from right to left, then put them out(to the console or file)from top to bottem. Like this,

a = 1; b = 2; c = 3;
cout<<a<<b<<c<<endl;
buffer:|3|2|1|<-   (take “<-” as a poniter)

output:|3|2|<-     (output 1)
        |3|<-       (output 2)
        |<-         (output 3)

Then I write a code below,

#include <iostream> 
using namespace std; 
int c = 6;
int f() 
{   
    c+=1; 
    return c; 
} 

int main() 
{ 
     int i = 0; 
     cout <<"i="<<i<<" i++="<<i++<<" i--="<<i--<<endl; 
     i = 0;
     printf("i=%d i++=%d i--=%d\n" , i , i++ ,i-- );

     cout<<f()<<" "<<f()<<" "<<f()<<endl; 
     c = 6;
     printf("%d %d %d\n" , f() , f() ,f() );
     system("pause");
     return 0; 
}

Under VS2005, the output is

i=0 i++=-1 i--=0
i=0 i++=-1 i--=0
9 8 7
9 8 7

Under g++( (GCC) 3.4.2 (mingw-special)), the output is,

i=0 i++=0 i--=1
i=0 i++=-1 i--=0
9 8 7
9 8 7

It seems that the buffer is like a stack. However, I read C++ Primer Plus today, and it is said that the cout work from left to right, every time return an object(cout), so "That’s the feature that lets you concatenate output by using insertion". But the from left to right way can not explain cout< output 9 8 7 Now I'm confused about how cout's buffer work, can somebody help me?

+4  A: 

This is not a bug, nor is it anything to do with output buffering.

The order of execution of the i-- and i++ operations is not defined when they're invoked more than once as parameters to the same function call.

To elaborate (and possibly correct) Iraimbilanja's mention of "sequence points", the cout version is equivalent to:

(((cout << a) << b) << c)

Effectively, it's actually three separate function calls, each of whose parameters are evaluated in order, even though it's written like a single statement.

The << operator is really ostream& operator<<(ostream& os, int), so another way of writing this is:

operator<< ( operator<< ( operator<< ( cout, a ), b ), c )

Since for the outer call it's not (AFAIK) defined which order the two parameters are evaluated, it's perfectly possible for the right-hand "c" parameter (or in your case "i--") to happen before the left hand parameter is evaluated.

Alnitak
Hi, Alnitak, I have a question that I think the cout buffer get the output from right to left, then put them out from right to left, too. But I think in your code, the cout buffer get the output from left to right, is that true? Thank you~
lucas
And in the g++, the cout <<"i="<<i<<" i++="<<i++<<" i--="<<i--<<endl; output i=0 i++=0 i--=1but in the vs2005, it outputi=0 i++=-1 i--=0Can you explain this?
lucas
Alnitak
I have a look at "C++ Primer Plus", it is said the left-to-right nesting is right. But I think the left-to-right way can not explain the cout<<f()<<" "<<f()<<" "<<f()<<endl; get output 9 8 7, is it?
lucas
good point - I've changed my explanation, I think it's now consistent, and explains your results, but also contradicts the accepted answer.
Alnitak
It is becoming clear to me now~ Thanks for your help~
lucas
+5  A: 

The output of:

printf("i=%d i++=%d i--=%d\n" , i , i++ ,i-- );

is unspecified. This is a common pitfall of C++: argument evaluation order is unspecified.

Not so with the cout case: it uses chained calls (sequence points), not arguments to a single function, so evaluation order is well defined from left to right.

Edit: David Thornley points out that the behavior of the above code is in fact undefined.

It's worse than unspecified; it's undefined. There are no guarantees that the result will match any order of evaluation, although that's usually what happens given the obvious implementation. However, +1 for the explanation of the cout case.
David Thornley
A: 

if possible try updating to gcc >= 4. i just ran this on 4.0.1 and it executes just dandy.

contagious
While gcc 3.x is very very old and updating might be a good idea in general, in this case the point is that none of the results is the "correct" one. It's just unspecified, and relying on unspecified behavior might change from one compiler version to the next.
janneb
Given that this is undefined behavior, (a) any behavior is just dandy according to the standard, and (b) you don't know whether it will give the behavior you expect on any other version, any other compiler options, or any other surrounding code.
David Thornley