C 语言 stdio 缓冲原理
更新时间:2026-08-26。本文是
languages/c/主题高手层的骨架文档(占位),完整展开将在后续批次补齐。
本文要回答的问题
printf之后数据真的马上到文件/终端了吗?- 为什么管道里 printf 的输出顺序会乱?无缓冲的行缓冲是什么?
- 一个
printf多次调用 vs 拼好一次写,差在哪?
一、三级缓冲
printf/fprintf 先写进用户态缓冲区,攒够才触发一次 write 系统调用:
| 缓冲类型 | 触发时机 | 适用 |
|---|---|---|
| 全缓冲 | 缓冲区满(默认 4-8KB)或 fflush/fclose | 重定向到文件 |
| 行缓冲 | 遇到 \n | 终端(stdout) |
| 无缓冲 | 立即写 | stderr |
坑:stdout 到终端是行缓冲、重定向到文件是全缓冲——所以 printf 后马上 fork/崩溃,日志可能丢(缓冲没刷)。stderr 无缓冲,错误信息即时可见。
二、关键函数
c
setvbuf(fp, NULL, _IONBF, 0); /* 关闭缓冲 */
setvbuf(fp, buf, _IOFBF, 4096); /* 自定义全缓冲 */
fflush(stdout); /* 手动刷盘 */fflush 是"强制现在写",也是调试时让日志立刻落盘的惯用手段。
三、性能差异
- 1000 次
printf各一行:全缓冲可能只触发几次write;逐行无缓冲则触发 1000 次系统调用。 - 系统调用是性能分水岭(用户态↔内核态切换),见 strace 观察系统调用。
- 策略:少调用、大缓冲、批量拼好再写(衔接 字符串性能)。
四、与入门层的衔接
- fopen/fclose 与流概念,见 fopen 与 fclose。
- fputc/fputs 逐字符/逐串写的差异,见 fputc 与 fputs。
一句话总结
stdio 缓冲是"攒一批再交出去"的批发商:文件全缓冲、终端行缓冲、stderr 无缓冲,批量写减少系统调用就是性能,日志丢失时先怀疑缓冲没刷。
本文为骨架文档:核心结构已就位,示例代码与实测数据将在后续批次补齐。