为什么write()在输出重定向中的printf()之前打印?

时间:2012-02-29 00:03:03

标签: c

所以我知道printf()的级别高于write(),最终会使用write()。缓存Printf()write()进行系统调用。

示例1,如果我在printf()之前运行write()的程序,那么它会在值printf()之前输出write()的值。

示例2,如果我要运行相同的程序并让它通过输出重定向到文件中,则write()的值在printf()之前输出。

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("This is a printf test\n");
    write(STDOUT_FILENO, "This is a write test\n", 21);
    return 0;
}

我不明白这里发生了什么。在示例1中,程序是否在运行printf()之前等待write()输出?在示例2中,程序是否重定向准备好的第一个输出?因为write()是较低级别,并且不需要像printf()那样缓冲,那么它会先打印出来吗?

3 个答案:

答案 0 :(得分:6)

你回答了自己的问题。

printf已缓存且write未缓存。

为了输出到终端,C stdio系统有一个功能,即只要看到换行符'\n'就会刷新缓冲区。有关stdio缓冲的更多信息,请查看setvbuf的文档。

但是当输出到文件以提高速度时,stdio系统不会刷新缓冲区。这就是首先出现write输出的原因。

以下是在我的Linux系统上运行的一些strace输出:

  

fstat(1,{st_mode = S_IFCHR | 0620,st_rdev = makedev(136,1),...})= 0
  mmap(NULL,4096,PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS,-1,0)= 0x7f7880b41000
  写(1,“这是一个printf测试\ n”,22)= 22
  write(1,“这是写测试\ n \ 0”,22)= 22

fstat是stdio系统检测到连接的输出文件描述符1的类型的地方。我相信它会查看st_mode并看到它是一个角色设备。磁盘文件是块设备。 mmap是stdio缓冲区的内存分配,即4K。然后写入输出。

答案 1 :(得分:2)

这与C标准库完成的输出缓冲有关。在第一种情况下,由于你在终端上写,libc完成的缓冲是面向行的(每次回车都强制刷新),立即在屏幕上显示文本,特权交互性能(不应该是一个问题,因为预计终端不会成为负载文本的目标。因此,printf输出会立即写入一些write调用,该调用将在您明确发出的下一个调用之前发生。

在第二种情况下,libc检测到你正在写一个文件,因此,为了提高性能,它启用了缓冲;因此,通常第一个printf将不会立即提交,并且您的write将在libc实际刷新缓冲区之前发生。

同样,这就是通常发生的事情。我不认为这种行为是由任何标准强制实施的 编辑: 实际上,这是由C99强制执行的,请参阅@ Jonathan的评论)(和在第二个示例中,即使启用了缓冲,库也可能决定执行刷新,例如,如果缓冲区被printf填充。

答案 2 :(得分:0)

内部printf在其缓冲区已满时将使用write。如果它检测到它正在写入交互式输出(例如尚未重定向的stdout),它也可能在缓冲区已满之前执行写入。