C库函数提供三种缓冲机制,分别是下图中的unbuffered无缓存、block buffered块缓存(也称全缓存,会把缓存块写满,然后一次性刷入磁盘)和line buffered行缓存。 在man setbuffer中可以看到三种缓存的说明;
下面是各种缓存的中文说明
C库并提供了三种函数修改缓存,可见man setbuffer
前三个函数是最后一个声明setvbuf的封装,在man手册中有说明。
The setbuf() function is exactly equivalent to the call
setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
Thesetbuffer()functionisthesame,except that the size of the buffer is up to the caller,
rather than being determined by the default BUFSIZ.
the setlinebuf() function isexactlyequivalent to the call:
setvbuf(stream, NULL, _IOLBF, 0);
Setvbuf中的形参but表示自定义的缓冲区,如果为NULL,会由c库自行分配。如果不为NULL,第4个参数size则为缓冲区大小。第三个参数mode是指缓冲区类型,_IONBF指io no buffer即无缓存, _IOLBF指line行缓存,_IOFBF指full全缓存 。
下面是原文
测试一下行缓存,查看以下代码:
会有怎样的输出呢?见下图:
为什么“father line 1 ”会被输出两次?原因是默认C运行库是使用行缓存,行缓存是直到遇到’ ’才将缓存内容刷到标准输出,否则会一直存着,直到缓冲区满了为止才刷新。
在第6行代码执行后,c库并未将输出结果立即刷到标准输出,因此还停留在缓冲区中。子进程会继承父进程的缓冲区,因此子进程缓存区中也包括了
“father line 1 ”。
原理清楚了,解决的方法必然是强制刷新缓存就行了,这可以用fflush函数来完成,fflush的声明及帮助如下:
注意,flush的参数类型是FILE*,我们必须传入相同参数类型,这是C库头文件/usr/include/stdio.h中定义的,
但是我们要将输出刷新到屏幕,即标准输出stdout,因此我们可以通过man stdout获得相应帮助,如下图所示:
这里声明的是extern,即外部的,那stdin在哪里呢?依然是在stdio.h中,如下图所示:
好,让我们加上fflush函数,代码如下 。
程序输出结果如下,符合预期:
再来一个方法,通过setbuf来搞定。
执行结果如下:
打完收工。