标准库的I/O缓冲区
- 全缓冲:如果缓冲区写满了就写回内核。常规文件通常是全缓冲的。
- 行缓冲:如果用户程序写的数据中有换行符就把这一行写回内核,或者如果缓冲区写满了就写回内核。标准输入和标准输出对应终端设备时通常时行缓冲的。
- 无缓冲:用户程序每次调库函数做写操作都要通过系统调用写回内核。标准错误输出通常是无缓冲的,这样用户程序产生的错误信息可以尽快输出到设备。
何时会刷新缓冲区?
- 缓冲区满时,自动刷新缓冲区
- 调用exit()函数退出程序
- 函数return时
- 调用fclose函数时
- 调用fflush函数时
- 对于行缓冲,遇到“\n”时,比如终端输入时
缓冲区大小
行缓冲为1024byte,全缓冲为4096byte。
验证程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char *argv[]){
char teststr[1030];
int i;
for(i=0;i<1030;i++){
teststr[i]='a';
}
FILE *fp;
fp=fopen(argv[1],"w");
fwrite(teststr,1,sizeof(teststr),fp);
_exit(-1);
}
该程序最终在test文件内输出1024个‘a’,即写满缓冲区后自动刷新。剩余6个a因为_exit()函数强制退出不刷新缓冲区所以并未输出成功。
_exit&exit
- _exit直接结束程序进入内核
- exit将缓冲区刷新再退出程序
_exit不刷新缓冲区验证程序:
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("hello\n");
printf("world");
_exit(0);
}
最终只输出hello,因为行缓冲遇到换行符刷新缓冲区,而没有输出world是因为_exit直接退出,并没有刷新缓冲区。
exit刷新缓冲区验证程序:
#include<stdio.h>
#include<stdlib.h>
int main(void) {
printf("hello\n");
printf("world");
exit(0);
}
最终输出hello和world。证明了exit函数退出时刷新缓冲区。
fflush函数
使用fflush函数,在未写满缓冲区的时候也可以写回内核,刷新缓冲区。
#include <stdio.h>
int fflush(FILE *stream);
我们这里引用man手册中对fflush函数的说明:
For output streams, fflush() forces a write of all user-space buffered data for the given output or update stream via the stream’s underlying write function.
For input streams associated with seekable files (e.g., disk files, but not pipes or terminals), fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application.
The open status of the stream is unaffected.
If the stream argument is NULL, fflush() flushes all open output streams.
For a nonlocking counterpart, see unlocked_stdio(3).
使用例子:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char *argv[]){
char teststr[1030];
int i;
for(i=0;i<1030;i++){
teststr[i]='a';
}
FILE *fp;
fp=fopen(argv[1],"w");
fwrite(teststr,1,sizeof(teststr),fp);
fflush(NULL);
_exit(-1);
}
最终输出1030个‘a’因为fflush强制刷新缓冲区。