未刷新stdout缓冲区是否会导致文件输出内容错误
结论
是的,如果你注释掉fflush(stdout)代码行,最终HelloWorld.txt中会同时写入Hello World 1和Hello World 2两条内容。
原因说明
首先需要明确两个核心概念的区别:
- 内核层面维护的文件描述符映射关系:
dup2系列函数修改的是这层映射,只会改变后续系统调用写文件时的目标,完全不会操作C标准库在用户空间维护的缓冲区数据 - C标准库(stdio)层面的用户态输出缓冲区:
printf这类stdio函数的输出内容会先暂存在这个缓冲区中,满足刷新条件才会真正调用系统调用写到内核对应的文件里
注释掉fflush(stdout)时的执行流程:
- 第一次执行
dup2(FILE1,STDOUT_FILENO)后,标准输出对应的底层文件描述符指向原终端输出 - 执行
printf("Hello World 1\n"),内容写入stdout的用户态缓冲区,此时如果没有触发自动刷新(比如如果标准输出被重定向到文件时默认是全缓冲,就算带换行也不会自动刷新),内容会一直留在缓冲区中 - 执行
dup2(FILE2,STDOUT_FILENO),修改了内核层面标准输出文件描述符的映射,指向HelloWorld.txt,但用户态缓冲区里的Hello World 1内容没有被清空也没有被写出 - 执行
printf("Hello World 2\n"),内容追加到同一个stdout缓冲区中 - 程序退出时,stdio会自动刷新所有打开的流缓冲区,此时缓冲区里的两条内容会一起写入当前标准输出对应的文件,也就是
HelloWorld.txt
保留fflush(stdout)时的执行流程:
fflush(stdout)会把当前缓冲区里的Hello World 1立刻刷入当时对应的底层文件(原终端输出),同时清空缓冲区。后续修改文件描述符后写入的Hello World 2是缓冲区里唯一的内容,程序退出时只会把这一条写入HelloWorld.txt。
对应测试代码
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int FILE1 = dup(STDOUT_FILENO); int FILE2 = open("HelloWorld.txt",O_WRONLY|O_CREAT,0666); dup2(FILE1,STDOUT_FILENO); printf("Hello World 1\n"); //THE LINE OF CONCERN fflush(stdout); dup2(FILE2,STDOUT_FILENO); printf("Hello World 2\n"); close(FILE2); close(FILE1); return 0; }
内容的提问来源于stack exchange,提问作者Futuristic Gladiator
相关产品推荐
相关产品推荐

