终端运行与重定向到文件时程序输出行数不同的原因
输出行数差异的原因
核心差异源于标准输出的缓冲策略不同:
- 终端设备默认采用行缓冲:当输出包含换行符时,立即刷新缓冲区,内容直接输出。
- 普通文件默认采用全缓冲:输出内容暂存缓冲区,直到缓冲区满、进程退出或主动调用
fflush时才会写入文件。
终端行缓冲场景(10行输出)
每次printf("hello\n")因包含换行符,会立即刷新缓冲区,缓冲区始终为空,fork时不会继承到未输出的内容:
- 第一次循环(i=0):
初始进程P0执行fork()产生子进程P1,随后P0和P1各自执行printf,直接输出2行。 - 第二次循环(i=1):
P0执行fork()产生P2,随后P0执行printf输出1行;P1执行fork()产生P3,随后P1执行printf输出1行;- 新产生的
P2和P3直接执行printf,各输出1行;
这一步共输出4行。
- 循环结束后:
P0、P1、P2、P3四个进程各自执行最后的printf,输出4行。
总计:2+4+4=10行。
文件全缓冲场景(12行输出)
全缓冲模式下,printf的内容暂存缓冲区,fork会完整复制父进程的地址空间(包括未刷新的缓冲区),导致缓冲区内容被多个进程重复输出:
- 第一次循环(i=0):
P0执行fork()产生P1,此时P0尚未执行printf,P1继承的缓冲区为空;P0和P1各自执行printf后,缓冲区各存入1行hello\n,未被刷新。
- 第二次循环(i=1):
P0执行fork()产生P2,P2继承了P0缓冲区里的1行内容;随后P0执行printf,缓冲区变为2行;P1执行fork()产生P3,P3继承了P1缓冲区里的1行内容;随后P1执行printf,缓冲区变为2行;P2执行printf,缓冲区变为2行;P3执行printf,缓冲区变为2行;
此时四个进程的缓冲区各有2行未输出内容。
- 循环结束后:
四个进程各自执行最后的printf,缓冲区各新增1行,变为3行。当进程退出时,缓冲区被刷新,每个进程输出3行,总计4*3=12行。
总结来说,终端下的行缓冲避免了fork时的缓冲区复制重复输出,而文件的全缓冲导致未刷新的内容被子进程继承,最终多输出了2行。
内容的提问来源于stack exchange,提问作者Ziad
相关产品推荐
相关产品推荐

