C语言重定向printf到文本文件后文件为空,WSL环境运行异常如何解决
问题原因分析
你遇到的现象差异本质是C标准库I/O缓冲区刷新策略的区别:
- 当stdout关联终端设备时,默认使用行缓冲,输出内容带
\n就会自动刷新缓冲区到内核 - 当stdout关联普通文件时,glibc默认使用全缓冲,只有缓冲区满、程序正常退出调用exit回调、或者主动调用fflush时才会把用户态缓冲区的内容写入文件
你的代码中printf输出后直接关闭了底层文件描述符fildes,此时C标准库的用户态缓冲区还没来得及刷新,内容直接被丢弃,所以文件为空。教授的虚拟机环境大概率是缓冲阈值设置更小,或者存在特殊的glibc补丁刚好触发了自动刷新,才出现符合预期的结果。
修复方案
你可以任选以下任意一种方案解决:
- 方案1:printf后主动刷新标准输出缓冲区
在printf调用后、close(fildes)前添加fflush(stdout);,强制把缓冲区内容写入文件。 - 方案2:使用系统调用write替代标准库printf
直接操作文件描述符绕过用户态缓冲区,将printf替换为write(STDOUT_FILENO, "Hi! My Name is \n", 16);即可。 - 方案3:提前修改stdout的缓冲模式为无缓冲
在close(1)之前添加setvbuf(stdout, NULL, _IONBF, 0);,之后所有stdout的输出都会直接写入文件,不需要等待缓冲区满。 - 方案4:关闭标准库文件指针而非直接关底层文件描述符
将close(fildes);替换为fclose(stdout);,fclose在关闭文件前会自动刷新未写入的缓冲区内容。
方案1修改后的完整代码示例
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(){ mode_t mode = S_IRUSR | S_IWUSR; close(1); int fildes = open("hello_world.txt", O_CREAT | O_TRUNC | O_RDWR, mode); printf("Hi! My Name is \n" ); fflush(stdout); // 新增刷新缓冲区的代码 close(fildes); return 0; }
内容的提问来源于stack exchange,提问作者jun
相关产品推荐
相关产品推荐

