zoukankan      html  css  js  c++  java
  • C++输入输出缓冲区的刷新问题

    当我们对文件流进行操作的时候,它们与一个streambuf 类型的缓存(buffer)联系在一起。这个缓存(buffer)实际是一块内存空间,作为流(stream)和物理文件的媒介。例如,对于一个输出流, 每次成员函数put  (写一个单个字符)被调用,这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。

    当缓存被排放出来(flush)时,它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话),或者简单的被抹掉(如果是一个输入流的话)。这个过程称为同步(synchronization),它会在以下任一情况下发生:

    1.程序正常结束。作为main返回工作的一部分,将清空所有的输出缓冲区。

    2.在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。

    3.用操纵符显示地刷新缓冲区,如用endl。

    4.在每次输出操作执行完毕后,用unitbuf操纵符设置流的内部状态,从而清空缓冲区。

    5.可将输出流与输入流关联起来,在读输入流时将刷新其关联的输出缓冲区。

    在C++中,cin, cout, cerr 分别于stdin, stdout, stderr对应的。即iostream流对象分别与cstdio对应,关系如下:

    image

    同步即表明我们可以在程序中混合用cout和printf或其他对应的流对,并不会引起流指针的混乱。可以用std::ios_base::sync_with_stdio(false)来取消这种同步,取消后,如下程序中cout和printf就不是按照预期的顺序输出

    #include <iostream>
    #include <stdio.h>

    using namespace std;

    int main() {
    ios_base::sync_with_stdio(false);
    for(int i = 0; i < 10; i++) {
    cout << "1 ";
    printf("2 ");
    }
    cout << endl;
    printf(" ");
    return 0;
    }

    结果为:

    这表明在调用std::ios_base::sync_with_stdio(false)后,cout与stdout不再共享同一块缓冲区。它们是分别管理自己的缓冲区的。

    正是因为这种同步,所以cin、cout比scanf、printf速度要慢,如果我们在使用cin、cout输入输出前加一句std::ios_base::sync_with_stdio(false),其实速度和scanf、printf差不多。原因请看

    https://www.byvoid.com/blog/fast-readfile

    因为默认情况下,cin是和cout绑定的,cin 会刷新cout的缓冲区,可以用函数cin.tie(0)来解绑定。所以在以下代码中应该是不会引起缓冲区刷新的:

    #include <iostream>
    #include <stdio.h>
    using namespace std;


    int main(){
    char buf[256];
    // setbuf(stdout, buf);

    cin.tie(0);
    for(int i = 0; i < 10; i++)
    cout << "1 " ;
    cout << " ";
    int a, b;
    cin >> a >> b;
    cout << endl;

    }

    结果:

    发现还是输出了缓冲区,如果我们先设置一下stdout的的缓冲区,不要默认的缓冲区试试(即在上面代码中去掉注释)结果为:

    可以看到是我先输入数字1和2之后,然后执行cout <<endl ,此时刷新缓冲区,输出的11111111   

    具体原因可以看stackoverflow中,不过貌似也没解释太清楚

    http://stackoverflow.com/questions/14052627/why-do-we-need-to-tie-cin-and-cout

    我简单总结了一下,大概是说tie这个函数在绑定了cout后,保证会在cin执行之前冲刷cout的缓冲区。如果你cin.tie(0)解除了绑定,那么并不会保证cout在cin之前冲刷,但也不保证不会冲刷。

    但它并没有解释为什么我设置了自己的缓冲区,它就不因为执行cin而冲刷cout的缓冲区了。

    Reference:

    http://www.cnblogs.com/TenosDoIt/p/3733243.html

    http://blog.csdn.net/lesslie1992/article/details/14057417

  • 相关阅读:
    关于在Linux下的换行符 和windows下的换行符
    Linux文件操作标准接口
    tcpdump抓包和wireshark解包
    Makefile学习(1)
    域名服务器设置
    Linux系统移植(1)
    SQL基本语句整理
    ARM---搭建开发板的开发环境(x210v3s)
    C语言基础
    Oracle中的USEREVN()
  • 原文地址:https://www.cnblogs.com/lysuns/p/4278944.html
Copyright © 2011-2022 走看看