zoukankan      html  css  js  c++  java
  • clog,cout,cerr 输出机制

    clog:控制输出,使其输出到一个缓冲区,这个缓冲区关联着定义在 <cstdio> 的 stderr。

    cerr:强制输出刷新,没有缓冲区。

    cout:控制输出,使其输出到一个缓冲区,这个缓冲区关联着定义在 <ostream> 的 stdout。

    但是我们分别测试如下三个程序的结果如下:

    cout:

    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char const *argv[])
    {
        cout << "ERROR!!";
        while (true);
        return 0;
    }

    输出结果为:

        

    可以理解,因为 cout 输出是有缓冲区的,这里没有输出说明缓冲区还没有刷新。

    cerr:

    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char const *argv[])
    {
        cerr << "ERROR!!";
        while (true);
        return 0;
    }

    输出:

        

    可以理解,因为 cerr 没有输出缓冲区,是强制刷新的,所以在循环之前就已经刷新了,所以会打印结果。

    clog:

    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char const *argv[])
    {
        clog << "ERROR!!";
        while (true);
        return 0;
    }

    输出:

        

    这个比较奇怪,不是说 clog 是由缓冲区的嘛,为什么它不是像 cout 一样的输出呢?先看下面部分:

    对于cout,clog,cerr输出的机制,c跟c++的标准做法是:

    stderr : 预设没有分配 buffer
    
    stdout :预设有分配 buffer
    
    cout :用 stdout 的buffer
    
    clog :用 stderr 的 buffer
    
    cerr :用 stderr 的buffer,强制清空 buffer

    其中,stderr 的 buffer 预设为没有,所以 clog 和 cerr 都是直接在屏幕输出而没有在缓冲区驻留。所以前面 clog 的输出结果也就可以理解了,因为缓冲区是空的,那么输出就不会在缓冲区驻留了。

    下面来说说 cout,clog,cerr 的输出顺序,也可作为 clog 一个更深入的理解。

    先看下面一段代码:

    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char const *argv[])
    {
        setbuf(stderr,0);
        cout << "123";
        clog << "456";
        cerr << "789";
    
        return 0;
    }

    它的输出结果是:

      456123789

    上面代码中,setbuf 为 0,也就是设置 stderr 的缓冲区为 0,因为 stderr 的值是有可能因为编译器的不同而不同的,前面说的 c++ 机制只是标准机制,编译器实现商可以进行自己的改变的。

    现在来理解一下输出的结果,首先 clog 的输出在最前面很容易理解,但是为什么 cout 的输出在 cerr 的前面呢,因为cerr 的输出关联到了 cout,也即 cerr.tie()=&cout,所以当 cerr 要清空时,会先清空前面的 cout 的缓冲区。[注意只是 cerr 前面的 cout ]

    看另一段代码:

    #include <iostream>
    
    using namespace std;
    
    char buf[10];
    int main(int argc, char const *argv[])
    {
        setbuf(stderr,buf);
        cout << "123";
        clog << "456";
        cerr << "789";
    
        return 0;
    }

    此时的输出是:

      123456789

    在这里给 stderr 的缓冲区设为了 buf,不再是 0 了,所以这里输出结果按顺序输出。

    下面取消 cerr 和 cout 的关联:

    #include <iostream>
    
    using namespace std;
    
    char buf[10];
    int main(int argc, char const *argv[])
    {
        cerr.tie(0);
        setbuf(stderr, buf);
        cout << "123";
        clog << "456";
        cerr << "789";
    
        return 0;
    }

    输出结果为:

      456789123

    这里 clog 在 cout 前面输出,因为 cerr 输出的时候强制刷新了 stderr 缓冲区。

    cerr 和 clog 位置调换,结果为:

    #include <iostream>
    
    using namespace std;
    
    char buf[10];
    int main(int argc, char const *argv[])
    {
        cerr.tie(0);
        setbuf(stderr, buf);
        cout << "123";
        cerr << "789";
        clog << "456";
    
        return 0;
    }

    输出结果:

      789123456

    此时 cerr 最先输出,因为强制刷新,而 clog 因为缓冲区不为空,所以会在程序结束的时候执行 flush。

    再来说说 clog 和 cerr 的重定向问题。

    直接对 cerr 和 clog 的输出使用重定向符 > 是无效的,这两个的输出一定会打印在终端上,但是如果一定要进行重定向,那么可以用  rdbuf 函数,如下:

    ofstream ofs("logfile");
    clog.rdbuf(ofs.rdbuf());
    clog << "Goes to file." << endl;

    以上测试结果都是在mac g++4.2.1 测试的结果,输出结果在mac的终端。在windows下面测试的结果可能不同。 

    具体的区别可以参考如下内容:【以下内容来源:http://tieba.baidu.com/p/937433213】

    1.该物件所用的stream是否按照规定分配buffer
    全缓冲:buffer满了才执行fflush()
    行缓冲:buffer满了or碰到换行字元才执行fflush()
    无缓冲:不管buffer有没有满都执行fflush()


    console下
                标准     windows    linux
    stdout| 行/无缓冲|全缓冲   |行缓冲    |
    stderr| 行/无缓冲|全缓冲   |无缓冲    |

    非console
                标准      windows   linux
    stdout|  全缓冲    |全缓冲   |全缓充    |
    stderr|  行/无缓冲|全缓冲   |无缓冲    |

    以上是预设值,有一点要厘清,全/行/无缓冲只是该stream的特性,
    与它有没有buffer并没有关系,拿windows来说,
    乍看之下会等到buffer满才输出,但实际上是直接输出,
    因为没有分配buffer,你也可以对无缓冲的stream分配buffer,
    虽然一样直接跑fflush()就是了

    如果要分配buffer给stream,可以用setbuf()和setvbuf(),
    用前者时要注意,一但用它分配buffer后,行缓冲的特性会消失,
    且buffer不能是局部变量,因为最后一次fflush()是在exit()里执行
    那时局部变量已经被释放


    2.该物件是否按照规定设置ios::unitbuf
    如果有设ios::unitbuf,就直接执行fflush(),
    即使底下stream设成全缓冲跟分配buffer也一样,
    除非手动设定,否则只有cerr才有设ios::unitbuf

    如果要修改物件的ios::unitbuf,可用setf()或unsetf()设定


    3.该物件的是否按照规定绑定别的物件

                  标准  windows  linux
    clog.tie()| null |&cout|   null |
    cerr.tie()|&cout|&cout|  &cout|
    cout.tie()|null  | null  |    null |

    如果有绑别的物件,当自己准备要跑fflush()时,
    会先让被绑定的物件执行fflush(),然后才换自己跑fflush()

    如果要修改绑定的物件,就用tie()来设,传0代表不绑定

    虽然下列网站写cin、cerr、clog都绑定cout, 
    http://www.cplusplus.com/reference/iostream/ios/tie/
    但是C++的规格书上,其实没规定clog要绑cout

    4.换行字元跟endl
    前者只能让行缓冲的物件跑fflush(),
    后者则强迫cout、cerr、clog跑fflush()

    5.如果一直到main()结束都没有跑fflush()
    那么stdout会先输出,接著才是stderr

    7.main()结束后,不可再用cout、cerr、clog来输出
    首先来看exit()的标准流程

    A.摧毁thread物件
    B.摧毁global物件/摧毁函式里的static物件/执行atexit注册函式
    C.让所有的C stream执行fflush(),接著关闭它们
    D.砍掉暂存档
    E.归还控制权给OS


    在执行dtor/atexit注册函式时,无法保证cout、cerr、clog这些物件还在

    总结:
    没分配buffer、无缓冲、ios::unitbuf!=0、buffer已满、行缓冲碰到' '、endl
    以上只要有一个成立就会跑fflush()

  • 相关阅读:
    hdu5894 hannnnah_j’s Biological Test(组合数取模)
    HDU5883 The Best Path(并查集+欧拉路)
    HDU5881 Tea(简单题)
    组合数取模
    codeforces703D Mishka and Interesting sum(区间偶数异或)
    upcoj2679 Binary Tree(思路题)
    upcoj2673 It Can Be Arranged(isap)
    atom编辑器适用
    python库pandas
    fabric Node SDK进行连接
  • 原文地址:https://www.cnblogs.com/xiezhw3/p/4349766.html
Copyright © 2011-2022 走看看