tags:

views:

966

answers:

5
+7  A: 

You are mixing a lot of things. To date:

  • Implementation details of cout
  • Chained calls
  • Calling conventions

Try to read up on them separately. And don't think about all of them in one go.

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

The above line invokes undefined behavior. Read the FAQ 3.2. Note, what you observe is a side-effect of the function's calling convention and the way parameters are passed in the stack by a particular implementation (i.e. yours). This is not guaranteed to be the same if you were working on other machines.

I think you are confusing the order of function calls with buffering. When you have a cout statement followed by multiple insertions << you are actually invoking multiple function calls, one after the other. So, if you were to write:

cout << 42 << 0;

It really means: You call,

cout = operator<<(cout, 42)

and then use the return in another call to the same operator as:

cout = operator<<(cout, 0)

What you have tested by the above will not tell you anything cout's internal representation. I suggest you take a look at the header files to know more.

dirkgently
+1  A: 

What you see is undefined behavior.

Local i and global c are added/subtracted multiple times without sequence point. This means that values you get can be about anything. Depends on compiler, possibly also processor architecture and number of cores.

The cout buffer can be thought as queue, so Alnitak is right.

eidolon
+3  A: 

Just as a general tip, never ever use i++ in the same line as another usage of i or i--.

The issue is that function arguments can be evaluated in any order, so if your function arguments have any side-effects (such as the increment and decrement operations) you can't guarantee that they will operate in the order you expect. This is something to avoid.

The same goes for this case, which is similar to the actual expansion of your cout usage:

function1 ( function2 ( foo ), bar );

The compiler is free to evaulate bar before calling function2, or vice versa. You can guarantee that function2 will return before function1 is called, for example, but not that their arguments are evaluated in a specific order.

This becomes a problem when you do something like:

function1 ( function2 ( i++), i );

You have no way to specify whether the "i" is evaluated before or after the "i++", so you're likely to get results that are different than you expect, or different results with different compilers or even different versions of the same compiler.

Bottom line, avoid statements with side-effects. Only use them if they're the only statement on the line or if you know you're only modifying the same variable once. (A "line" means a single statement plus semicolon.)

Dan Olson
+1  A: 

In addition to the other answers which correctly point out that you are seeing undefined behavior, I figured I'd mention that std::cout uses an object of type std::streambuf to do its internal buffering. Basically it is an abstract class which represents of buffer (the size is particular to implementation and can even be 0 for unbufferd stream buffers). The one for std::cout is written such that when it "overflows" it is flushed into stdout.

In fact, you can change the std::streambuf associated with std::cout (or any stream for that matter). This often useful if you want to do something clever like make all std::cout calls end in a log file or something.

And as dirkgently said you are confusing calling convention with other details, they are entirely unrelated to std::cout's buffering.

Evan Teran
A: 

In addition, mixing output paradigms (printf and cout) are implementation specific.

Tommy Hui