对,这里的缓冲区相当于堆 栈的效果

a = 1; b = 2; c = 3;


buffer:|3|2|1|<-   (take “<-” as a poniter)

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

#include <iostream>
using namespace std;
int c = 6;
int f()
    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() );  
     return 0;
Under VS2005, the out put is

i=0 i++=-1 i--=0i=0 i++=-1 i--=09 8 79 8 7
But under g++( (GCC) 3.4.2 (mingw-special)), the out put is,

i=0 i++=0 i--=1i=0 i++=-1 i--=09 8 79 8 7
g++的输出有点出乎我的意料之外。原以为这是一个 bug in g++,于是去so上问了下
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.


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.


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.

看到这里,如果我告诉你上面关于那个“cout和printf的输出是先从右往左读入缓冲区,再从top到bottem输出”完全是瞎扯的话,你的第一反应是什么?不会吧,我的机器上也是这样的结果之类的云云?其实这是一个参数调用顺序的问题,而很不幸的是,C/C++里,关于参数调用的顺序是一个 undefined behavior,也就是说,不管什么顺序的调用都是合理的,这依赖于compiler的实现。当然,如果参数的传递是用stack来实现的话,很有可能就是上面的结果。


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.


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.)


n 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.


关于implementation-defined unspecified和undefined这3种行为,可以参考这个


> i = 0;
> printf("i=%d i++=%d i--=%d\n" , i , i++ ,i-- );函数参数计算顺序(不是压栈顺序)是依赖编译器的,平时这么写不是好习惯。

也有人跟我讲cout<<a<<b<<c 的调用原型其实是 operator<< ( operator<< ( operator<<

int i=1;

如果是c++重载了的操作符,它就不是“操作符”,而是函数了, 但是其优先级别和计算顺序是保留的。所以,
ostream i;
等价于 (op<<(i, a))<<b<<c
等价于 op<<((op<<(i, a), b)<<c
等价于 op<<(op<<((op<<(i, a), b), c)

因为op<<((op<<(i, a), b)可能现于c计算,(op<<(i, a))可能先于 b 计算,但怎样的结果都是合理的。


下面来做一些试验(环境:g++ (GCC) 3.2.3 (mingw special 20030504-1))。#include <iostream>
using namespace std;int main() {
    cout << "aaa";
    return 0;
}输出为:aaabbb没有问题。如果将程序修改一下:#include <iostream>
using namespace std;int main() {
    cout << "aaa";
    return 0;
}输出成了:bbbaaa顺序发生了错误。sync_with_stdio()是在<ios_base>中定义的,当其接受true作为参数时,将会同步iostream与 stdio中的流操作。默认是true,因此第一个程序的结果是正确的。然而,尽管C++标准中规定stdio sync标志默认是true,不同平台下的不同编译器可能并不完全支持这个标准。因此也就有了通常意义上的关于“不要混用iostream与stdio” 之类的警告。如果再修改一下程序:#include <iostream>
using namespace std;int main() {
    cout << "aaa" << flush;
    return 0;


个人分类: 我的程序员之路
想对作者说点什么? 我来说一句