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对应,关系如下:

同步即表明我们可以在程序中混合用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("\n");
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 << "\n";
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

时间: 2024-11-08 09:34:15

C++输入输出缓冲区的刷新问题的相关文章

c语言输入输出缓冲区的概念

语言输入输出缓冲区的概念 你肯定会奇怪为什么一开始先说这个,一开始不都是数据类型什么的嘛,这个写在最前面因为后面的程序即使最简单的code都会用到输入输出,输出比较简单,可以放在后面再说,但是输入就不同了,如果不先了解一下,可能会得到和你预想不同的结果哦^_^.也正是由于和一般的c语言介绍方式不同,为了看起来正规一些,我就把这章叫做chapter0了,完全可以先跳过去,直接看chapter1. 1.getchar 先引用一下前人的成果(有修改)^_^:http://blog.csdn.net/c

C/C++中关于输入输出缓冲区和流的概念理解

(本文章关于缓冲区概念的理解部分取自:http://developer.51cto.com/art/201107/277186.htm) 首先可以看下快递的寄送过程: 源地址(商家的仓库)——中转地(快递公司的仓库)——目的地(买家) 我们从淘宝商家买衣服,商家通过快递公司把商品送到我们手里的这个过程可以形象的解释下缓存区和流的这个概念. 1, 淘宝商家不会亲自把商品给买家送过来的,因为这样效率太低了,商家会通过快递公司这个中转,然后快递公司再把东西送给买家.淘宝商家就是在键盘上打字,买家就是程

c/c++ 输入输出缓冲区

关于缓冲区的详细介绍,请参考 C++编程对缓冲区的理解 CPP的输入输出流和缓冲区 c++输出缓冲区刷新 (1)c++中cin.cout,cerr和c的stdin.stdout.stderr都是同步的,即iostream 对象和 and cstdio流是同步的,同步关系如下: 同步即表明我们可以在程序中混合用cout和printf或其他对应的流对.可以用std::ios_base::sync_with_stdio(false)来取消这种同步,取消后,如下程序中cout和printf就不是按照预期

java io流二-字符流输入输出缓冲区

/* 字符写入缓冲流 缓冲区的出现时为了提高流的操作效率. 所以在创建缓冲区之前,必须要现有流对象. Writer对应BufferedWriter Reader对应BufferedReader 该缓冲区中提供了一个换行符方法,newLine(); */ import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { FileWriter fw=new

55&gt;&gt;c++ 缓冲区的刷新

利用string 对象查看缓冲区的变化,因为每个string对象在输入时会以空格作为分界. #include<iostream> #include<string> using namespace std; int main() { string s1; string s2; string s3; cout<< "this is a while circle, and it's different with getline():"<<end

c++中cout&lt;&lt;未刷新缓冲区及未遇endl便输出的问题

今天在mac的xcode上直接写cout<<未遇到enl以及未刷新缓冲区数据就不能输出. 记得以前在vs以及g++上都会直接输出,之后查阅的c++输入输出缓冲区刷新的问题,解决了这个矛盾. 缓冲区清空的情况: 1.程序正常结束.作为main返回工作的一部分,将清空所有的输出缓冲区. 2.在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新. 3.用操纵符显示地刷新缓冲区,如用endl. 4.在每次输出操作执行完毕后,用unitbuf操纵符设置流的内部状态,从而清

10 python从键盘获取输入、刷新缓冲区

1 ---python从键盘获取输入有两种方法: 2 3 4 input与raw_input比较: 5 6 #1.input函数:需要以合法的python表达式形式输入 7 8 例1: 9 >>> name = input ("what is your name ?") 10 what is your name ? 11 12 当输入为数值型:3时,通过:当输入为字符型:lucy时,抱错: 13 14 例2: 15 str = input("Enter yo

C输入输出与文件

一.终端I/O 1.单字符I/O:getchar(),putchar() (1)单字符输入(get character): [ int getchar();] 返回值为输入的字符(ASCII).可以接受任何字符,包括非打印字符.当一次键入多个字符时按下回车键后getchar开始逐个读取所有字符(包括回车符). 在某些编译环境下,因为scanf()函数不读取回车符且将其留在输入队列中,下次调用scanf()时会由于先读取到回车符而在读取数据前过早结束输入,所以常在scanf后用[getchar()

输入输出与文件

输入输出与文件 一.终端I/O 1.单字符I/O:getchar(),putchar() (1)单字符输入(get character): [ int getchar();] 返回值为输入的字符(ASCII).可以接受任何字符,包括非打印字符.当一次键入多个字符时按下回车键后getchar开始逐个读取所有字符(包括回车符). 在某些编译环境下,因为scanf()函数不读取回车符且将其留在输入队列中,下次调用scanf()时会由于先读取到回车符而在读取数据前过早结束输入,所以常在scanf后用[g