简体   繁体   English

cout 的缓冲区是如何工作的?

[英]How the buffer of cout work?

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.几天前我知道cout有缓冲区,当我google它时,据说缓冲区有点像堆栈,从右到左获取cout的output和printf,然后将它们输出(到控制台或文件) 从上到下。 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 VS2005下output为

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".看来stack的方式是对的~不过,我昨天看了C++ Primer Plus,据说cout从左到右工作,每次返回一个对象(cout),所以“这就是让你连接output的功能通过使用插入”。 But the from left to right way can not explain cout<但是从左到右的方式不能解释 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 )",然后Alnitak告诉我,“<< 运算符实际上是 ostream& operator<<(ostream& os, int),所以另一种写法是: 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?现在我对 cout 的缓冲区如何工作感到困惑,有人可以帮助我吗?

You are mixing a lot of things.你混合了很多东西。 To date:迄今为止:

  • Implementation details of cout cout的实现细节
  • Chained calls链式调用
  • Calling conventions调用约定

Try to read up on them separately.尝试分别阅读它们。 And don't think about all of them in one go.并且不要在一个 go 中考虑所有这些。

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

The above line invokes undefined behavior.上面的行调用了未定义的行为。 Read the FAQ 3.2 .阅读常见问题解答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 (ie 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.我认为您将 function 调用的顺序与缓冲混淆了。 When you have a cout statement followed by multiple insertions << you are actually invoking multiple function calls, one after the other.当您有一个cout语句后跟多个插入<<您实际上是在调用多个 function 调用,一个接一个。 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:然后在对同一运算符的另一个调用中使用 return:

cout = operator<<(cout, 0)

What you have tested by the above will not tell you anything cout 's internal representation.您通过上述测试的内容不会告诉您任何cout的内部表示。 I suggest you take a look at the header files to know more.我建议您查看 header 文件以了解更多信息。

Just as a general tip, never ever use i++ in the same line as another usage of i or i--.就像一般提示一样,永远不要在同一行中使用 i++ 作为 i 或 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. 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:这种情况也是如此,这类似于您的 cout 使用的实际扩展:

function1 ( function2 ( foo ), bar );函数1(函数2(foo),bar);

The compiler is free to evaulate bar before calling function2, or vice versa.编译器可以在调用 function2 之前自由评估 bar,反之亦然。 You can guarantee that function2 will return before function1 is called, for example, but not that their arguments are evaluated in a specific order.例如,您可以保证 function2 在调用 function1 之前返回,但不能保证它们的 arguments 会按特定顺序进行评估。

This becomes a problem when you do something like:当您执行以下操作时,这会成为一个问题:

function1 ( function2 ( i++), i );函数1(函数2(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.您无法指定是否在“i++”之前或之后评估“i”,因此您可能会得到与预期不同的结果,或者不同编译器甚至相同编译器的不同版本的不同结果.

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.) (“行”表示单个语句加上分号。)

What you see is undefined behavior.您看到的是未定义的行为。

Local i and global c are added/subtracted multiple times without sequence point.局部i和全局c在没有序列点的情况下多次加/减。 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. cout缓冲区可以被认为是队列,所以 Alnitak 是对的。

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.除了正确指出您看到未定义行为的其他答案之外,我想我会提到std::cout使用std::streambuf类型的 object 进行内部缓冲。 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).基本上它是一个抽象的 class 代表缓冲区(大小特定于实现,对于无缓冲 stream 缓冲区甚至可以为 0)。 The one for std::cout is written such that when it "overflows" it is flushed into stdout. std::cout的一个写成这样,当它“溢出”时,它会被刷新到 stdout。

In fact, you can change the std::streambuf associated with std::cout (or any stream for that matter).实际上,您可以更改与std::cout关联的std::streambuf (或任何 stream )。 This often useful if you want to do something clever like make all std::cout calls end in a log file or something.如果您想做一些聪明的事情,例如使所有std::cout调用以日志文件或其他内容结尾,这通常很有用。

And as dirkgently said you are confusing calling convention with other details, they are entirely unrelated to std::cout's buffering.正如您所说的那样,您将调用约定与其他细节混淆了,它们与 std::cout 的缓冲完全无关。

In addition, mixing output paradigms (printf and cout) are implementation specific.此外,混合 output 范例(printf 和 cout)是特定于实现的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM