C语言 1000问 · 文件I/O Q2:标准 I/O 为什么要有缓冲?全缓冲 / 行缓冲 / 无缓冲分别在什么场景,fflush 有什么用?

来源:Flomo 原始笔记|查看原笔记|迁移日期:2026-10-31

C语言 1000问 · 文件I/O Q2:标准 I/O 为什么要有缓冲?全缓冲 / 行缓冲 / 无缓冲分别在什么场景,fflush 有什么用?

▎ 五大学习法:西蒙学习法——把「缓冲」钻透

为什么要缓冲

  • 系统调用(read / write)很「贵」:要陷入内核,可能要等磁盘 / 设备。
  • 若每次 fputc 都直接 write 一个字节,几百万次系统调用慢到不可接受。
  • 缓冲把多次小读写攒成一次大读写——典型的「批量换效率」。

三种缓冲模式

  1. 全缓冲:攒满整个缓冲区(如 4KB / 8KB)才真正写,默认用在「文件」上(非终端),系统调用最少、吞吐最高。

  2. 行缓冲:遇到换行 ‘\n’ 就刷一次(或缓冲满),默认用在「终端」(stdout 连终端时),交互程序能即时看到输出。

  3. 无缓冲:不缓冲、立即写;stderr 默认无缓冲,保证错误第一时间出来,哪怕程序马上崩溃。

默认约定

  • stdin / stdout:连终端 → 行缓冲;重定向到文件 → 全缓冲。
  • stderr:永远无缓冲。
  • 所以重定向到文件后,printf 的输出可能「延迟」出现,直到缓冲满或程序退出。

fflush 的作用

  • fflush(fp):把缓冲区里还没写出去的数据立刻写到底层。
  • 用途:程序崩溃 / 长时间不退出前确保日志落盘;调试时强制打印;多进程 / 多设备前保证数据一致。
  • fflush(NULL):刷新所有输出流。
  • 注意:对「输入流」用 fflush 在标准里是未定义行为(有的实现支持,但不可移植)。

缓冲带来的坑

  • 崩溃丢日志:printf 后程序崩溃、缓冲没刷,日志就丢了——关键处要用 stderr 或 fflush。
  • fork / exec 时缓冲被复制,可能重复输出。
  • 交互程序输出不实时:少了换行或没 fflush。
  • 多线程写同一个 FILE* 不是线程安全的,组合操作要自己加锁。

怎么控制缓冲

  • setvbuf(fp, buf, mode, size):设置缓冲模式和大小(_IOFBF 全缓冲、_IOLBF 行缓冲、_IONBF 无缓冲)。
  • setbuf(fp, NULL):关缓冲(等价 _IONBF)。
  • 嵌入式常用:给日志流设固定缓冲区或关缓冲,保证实时性和内存可控。

一句话:缓冲是「用一次系统调用换很多次小读写」;文件默认全缓冲、终端行缓冲、stderr 无缓冲,fflush 用来把缓冲立刻写下——日志程序崩溃丢日志,多半就是缓冲没刷。

📎 问题库(专栏⑭导航)→ https://v.flomoapp.com/mine/?memo_id=MjQ1NzM0NTk5

📎 文件I/O Q1(文本 vs 二进制)→ https://v.flomoapp.com/mine/?memo_id=MjU2NDUwNDAx

C语言