cout的缓冲区如何工作?
我几天前就知道cout有缓冲区,当我谷歌它时,据说缓冲区有点像堆栈,从右到左获取cout和printf的输出,然后将它们输出(到控制台或文件) )从上到下。 这样,
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)
然后我在下面写了一段代码,
#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;
}
在VS2005下,输出是
i=0 i++=-1 i--=0
i=0 i++=-1 i--=0
9 8 7
9 8 7
看来堆栈方式是对的~ 然而,我昨天读了C++ Primer Plus,据说cout从左到右工作,每次返回一个对象(cout),所以“这就是让你通过插入连接输出的功能”。 但从左到右的方式无法解释cout<
然后 Alnitak 告诉我,“<< 运算符实际上是 ostream& 运算符<<(ostream& os, int),所以另一种写法是: 运算符<< (operator<<(operator<<(cout, a), b), c)",
如果首先计算最右边的参数,则可以进行一些解释。
现在我对 cout 的缓冲区如何工作感到困惑,有人可以吗帮我?
I know that cout have buffer several days ago, and when I google it, 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
It seems that the stack way is right~
However, I read C++ Primer Plus yesterday, 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<
Then Alnitak tell me that, "The << operator is really ostream& operator<<(ostream& os, int), so another way of writing this is:
operator<< ( operator<< ( operator<< ( cout, a ), b ), c )",
If the rightest argument is first evaluated, it can be some explained.
Now I'm confused about how cout's buffer work, can somebody help me?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
你正在混合很多东西。 迄今为止:
cout
的实现细节尝试单独阅读它们。 并且不要一次性考虑所有这些。
上面的行调用未定义的行为。 阅读常见问题解答 3.2。 请注意,您观察到的是函数调用约定以及特定实现(即您的实现)在堆栈中传递参数的方式的副作用。 如果您在其他机器上工作,则不能保证这是相同的。
我认为您将函数调用的顺序与缓冲混淆了。 当您有一个
cout
语句后跟多个插入<<
时,您实际上是在一个接一个地调用多个函数调用。 所以,如果你要写:它的真正意思是:你调用,
然后在另一个调用中使用 return 来调用同一个运算符:
你通过上面测试的内容不会告诉你任何内容
cout
' s 的内部表示。 我建议您查看头文件以了解更多信息。You are mixing a lot of things. To date:
cout
Try to read up on them separately. And don't think about all of them in one go.
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:It really means: You call,
and then use the return in another call to the same operator as:
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.正如一般提示一样,切勿在同一行中使用 i++ 和 i 或 i-- 的其他用法。
问题是函数参数可以按任何顺序求值,因此如果您的函数参数有任何副作用(例如递增和递减操作),您无法保证它们会按照您期望的顺序运行。 这是要避免的事情。
这种情况也是如此,类似于 cout 用法的实际扩展:
function1 ( function2 ( foo ), bar );
编译器可以在调用 function2 之前自由评估 bar,反之亦然。 例如,您可以保证 function2 将在调用 function1 之前返回,但不能保证它们的参数按特定顺序求值。
当您执行以下操作时,这会成为一个问题:
function1 ( function2 ( i++), i );
您无法指定“i”是在“i++”之前还是之后计算,因此您可能会得到与预期不同的结果,或者使用不同的编译器甚至同一编译器的不同版本得到不同的结果。
最重要的是,避免带有副作用的陈述。 仅当它们是该行中唯一的语句或者您知道仅修改同一变量一次时才使用它们。 (“行”表示单个语句加分号。)
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.)
您看到的是未定义的行为。
局部
i
和全局c
在没有序列点的情况下多次加/减。 这意味着您获得的值可以是任何东西。 取决于编译器,也可能取决于处理器架构和内核数量。cout
缓冲区可以被认为是队列,所以 Alnitak 是对的。What you see is undefined behavior.
Local
i
and globalc
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.除了正确指出您看到未定义行为的其他答案之外,我想我会提到
std::cout
使用std::streambuf
类型的对象> 进行内部缓冲。 基本上它是一个代表缓冲区的抽象类(大小特定于实现,对于无缓冲流缓冲区甚至可以为 0)。std::cout
的编写方式是,当它“溢出”时,它会被刷新到 stdout。事实上,您可以更改与
std::cout
(或任何与此相关的流)关联的std::streambuf
。 如果您想做一些聪明的事情,例如使所有 std::cout 调用以日志文件或其他内容结束,这通常很有用。正如 dirkgently 所说,您将调用约定与其他细节混淆了,它们与 std::cout 的缓冲完全无关。
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 typestd::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 forstd::cout
is written such that when it "overflows" it is flushed into stdout.In fact, you can change the
std::streambuf
associated withstd::cout
(or any stream for that matter). This often useful if you want to do something clever like make allstd::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.
此外,混合输出范例(printf 和 cout)是特定于实现的。
In addition, mixing output paradigms (printf and cout) are implementation specific.