【问题标题】:the buffer and output sequence of cout and printfcout 和 printf 的缓冲区和输出序列
【发布时间】:2010-10-14 03:24:24
【问题描述】:

我知道 cout 和 printf 今天有缓冲区,据说缓冲区有点像堆栈,从右到左获取 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

在g++((GCC) 3.4.2 (mingw-special))下,输出为,

i=0 i++=0 i--=1
i=0 i++=-1 i--=0
9 8 7
9 8 7

似乎缓冲区就像一个堆栈。但是,我今天阅读C++ Primer Plus,据说cout从左到右工作,每次返回一个对象(cout),所以“这就是让你通过使用连接输出的功能插入”。但是从左到右的方式无法解释 cout

【问题讨论】:

    标签: printf buffer cout


    【解决方案1】:

    这不是错误,也与输出缓冲无关。

    i--i++ 操作在作为同一函数调用的参数被多次调用时,未定义它们的执行顺序。

    为了详细说明(并且可能是正确的)Iraimbilanja 提到的“序列点”,cout 版本相当于:

    (((cout << a) << b) << c)
    

    实际上,它实际上是三个独立的函数调用,每个函数的参数都按顺序计算,即使它写得像一条语句。

    &lt;&lt; 运算符实际上是ostream&amp; operator&lt;&lt;(ostream&amp; os, int),所以另一种写法是:

    operator<< ( operator<< ( operator<< ( cout, a ), b ), c )
    

    由于对于外部调用,它没有(AFAIK)定义两个参数的评估顺序,右侧的“c”参数(或在您的情况下为“i--”)完全有可能发生在左侧之前手参数被评估。

    【讨论】:

    • 嗨,Alnitak,我有一个问题,我认为 cout 缓冲区从右到左获取输出,然后也从右到左将它们输出。但是我认为在您的代码中, cout 缓冲区从左到右获取输出,这是真的吗?谢谢~
    • 在 g++ 中,cout
    • 我无法解释其中的区别,但我对我展示的从左到右的嵌套很有信心。该函数是 ostream& operator) 所以它必须这样嵌套。
    • 我看了一下《C++ Primer Plus》,据说从左到右的嵌套是对的。但我认为从左到右的方式无法解释 cout
    • 好点 - 我已经改变了我的解释,我认为它现在是一致的,并且解释了你的结果,但也与接受的答案相矛盾。
    【解决方案2】:

    输出:

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

    未指定。这是 C++ 的一个常见缺陷:参数评估顺序未指定。

    cout 情况并非如此:它使用链式调用(序列点),而不是单个函数的参数,因此评估顺序从左到右定义良好。

    编辑: David Thornley 指出上述代码的行为其实是undefined

    【讨论】:

    • 比未指定更糟糕;它是未定义的。无法保证结果将匹配任何评估顺序,尽管这通常是在明显实现的情况下发生的情况。但是,+1 用于解释 cout 案例。
    【解决方案3】:

    如果可能,尝试更新到 gcc >= 4。我刚刚在 4.0.1 上运行了它,它执行得很好。

    【讨论】:

    • 虽然 gcc 3.x 非常老旧,一般来说更新可能是一个好主意,但在这种情况下,关键是没有一个结果是“正确的”。它只是未指定,依赖未指定的行为可能会从一个编译器版本更改为下一个。
    • 鉴于这是未定义的行为,(a)根据标准,任何行为都只是花花公子,并且(b)您不知道它是否会在任何其他版本上给出您期望的行为,任何其他编译器选项,或任何其他周边代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    相关资源
    最近更新 更多