printf总是在遇到换行符时刷新缓冲区?

我的机器运行Ubuntu 10.10,并使用标准的GNU C库。 如果在格式化string中有一个换行符,那么printf会冲洗缓冲区,但是下面的代码似乎反复地改变了这个趋势。 有人可以澄清为什么缓冲区没有被刷新。

#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/wait.h> int main() { int rc; close(1); close(2); printf("HI 1\n"); fprintf(stderr, "ERROR\n"); open("newfile.txt", O_WRONLY | O_CREAT | O_TRUNC, 0600); printf("WHAT?\n"); fprintf(stderr, "I SAID ERROR\n"); rc = fork(); if (rc == 0) { printf("SAY AGAIN?\n"); fprintf(stderr, "ERROR ERROR\n"); } else { wait(NULL); } printf("BYE\n"); fprintf(stderr, "HI 2\n"); return 0; } 

运行该程序后,newfile.txt的内容如下。

 HI 1 WHAT? SAY AGAIN? BYE HI 1 WHAT? BYE 

不,标准说,如果可以确定输出设备是非交互式的,那么stdout最初是完全缓冲的。

这意味着,如果你将stdoutredirect到一个文件,它不会刷新换行。 如果你想尝试强制它行缓冲,使用setbufsetvbuf

C99的相关部分7.19.3 Files, paragraph 7规定:

在程序启动时,三个文本stream是预定义的,不需要明确打开 – 标准input(用于读取常规input),标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。 最初打开时,标准错误stream没有被完全缓冲; 标准input和标准输出stream是完全缓冲的,当且仅当stream可以被确定为不涉及交互设备时。

请记住第5.1.2.3/6节:

什么构成交互设备是由实现定义的。

如果输出设备是交互式的,例如terminal ,则刷新

如果可以确定输出设备是非交互式的,例如文件 ,则必须刷新输出缓冲区。 新行不会自动执行。

详情请参阅paxdiablo的答案 。

你有没有尝试明确调用fflush()来查看它是否改变了行为?

你有一种奇怪的幽默感。 🙂

 int main() { int rc; close(1); close(2); printf("HI 1\n"); fprintf(stderr, "ERROR\n"); 

closures用于stdout和stderr的文件描述符,然后立即尝试使用C stdout和stderr FILEstream。 不是一个好主意,我不确定C库会做什么来向您报告错误, 但崩溃将是一个可以接受的可能性

除此之外,当你使用标准的IOstream函数来写时,缓冲部分取决于目的地。 如果你正在写一个terminal,那么通常的行为就是行缓冲。 如果您正在写入pipe道,文件或套接字,那么通常的行为是阻塞缓冲。 您可以使用setvbuf(3)函数更改缓冲行为。 有关缓冲行为的详细信息,请参阅联机帮助页。