题
我几天前就知道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<
然后 阿尔尼塔克 告诉我,“<< 运算符实际上是 ostream& operator<<(ostream& os, int),所以另一种写法是:运算符 << ( 运算符 << ( 运算符 << ( cout, a ), b ), c )",
如果首先评估最正确的论点,则可以进行一些解释。
现在我对 cout 的缓冲区如何工作感到困惑,有人可以帮助我吗?
解决方案
你正在混合很多东西。迄今为止:
- 实施细则
cout
- 链式调用
- 调用约定
尝试单独阅读它们。并且不要一次性考虑所有这些。
printf("i=%d i++=%d i--=%d " , i , i++ ,i-- );
上面的行调用未定义的行为。阅读常见问题解答 3.2. 。请注意,您观察到的是函数调用约定以及特定实现在堆栈中传递参数的方式的副作用(即你的)。如果您在其他机器上工作,则不能保证这是相同的。
我认为您将函数调用的顺序与缓冲混淆了。当你有一个 cout
语句后跟多个插入 <<
您实际上是在一个接一个地调用多个函数。所以,如果你要写:
cout << 42 << 0;
它的真正含义是:你打电话,
cout = operator<<(cout, 42)
然后在对同一运算符的另一个调用中使用 return ,如下所示:
cout = operator<<(cout, 0)
您通过上述测试不会告诉您任何信息 cout
的内部代表。我建议您查看头文件以了解更多信息。
其他提示
正如一般的尖端,永远使用我在同一行++作为的另一使用I或I - 。
的问题是,函数参数可以以任意顺序进行评估,所以如果你的函数的参数有任何副作用(如增减操作),你不能保证他们会在你所期望的顺序操作。这是一件避免的。
这同样适用于这种情况下,它类似于您的COUT使用的实际的膨胀:
功能1(函数2(富),巴);
在编译器可以自由调用函数2,或反之亦然之前evaulate巴。你能保证函数2将返回功能1被调用之前,例如,但不是说他们的论点是在一个特定的顺序进行。
这成为一个问题,当你做这样的事情:
功能1(函数2(I ++),I);
您没有办法来指定是否“i”是之前或者“我++”,所以你很可能得到的结果比预期的,或者说是不同的后评估了不同的编译器,甚至不同版本的不同结果相同的编译器。
底线,避免与副作用语句。只使用他们,如果他们上线的唯一陈述或者如果你知道你只是修改同一个变量一次。 (A “线” 指的是单个语句加上分号。)
你看到的是未定义的行为。
本地i
和全球c
被加/减多次而不序列点。这意味着,你得到的值可以是任何东西。取决于编译器,也可能处理器架构和核心数量。
在cout
缓冲器可以被认为是队列中,以便参宿是正确的。
在除了其他的答案正确其中指出,你所看到的未定义的行为,我想我会提到std::cout
使用类型std::streambuf
的目的是做它的内部缓冲。基本上,它是一个抽象类,其表示缓冲液(大小是特定实施并且甚至可以为0流unbufferd缓冲区)。一个用于std::cout
被写入,使得当其“溢出”,其冲洗到标准输出。
在实际上,可以改变与std::streambuf
相关联的std::cout
(或就此而言的任何流)。如果你想要做的很漂亮像让所有std::cout
调用日志文件或东西到底这常常是有用的。
和作为 dirkgently说你是混淆调用约定与其它细节,它们是完全无关到std ::法院的缓冲。
另外,混合输出范式(printf和COUT)是实现特定的。