FILE *“/ dev / stdout”和stdout之间的区别

让我们来看看这个Hello World程序

#include <stdio.h> int main(int argc, char ** argv) { printf("Hello, World!"); const char* sFile = "/dev/stdout"; // or /proc/self/fd/0 const char* sMode = "w"; FILE * output = fopen(sFile, sMode); //fflush(stdout) /* forces `correct` order */ putc('!', output); // Use output or stdout from stdio.h return 0; } 

当使用output文件描述符进行编译时,输出是:

 !Hello, World! 

当使用stdio.h提供的stdout文件描述符进行编译时,输出如预期的那样:

 Hello, World!! 

在调用putc后,我们会直接打印到stdout ,在/dev/stdout上使用文件描述符时,会打开一个pipe道并打印到该pipe道中。 我不确定。

这个行为更加有趣,因为它不会覆盖“Hello”的第一个字符,而是将自己推到已经被压入的string前的行缓冲区的第一个位置。

从逻辑的angular度来看,这是意想不到的。

任何人都可以解释这里究竟发生了什么?


我用cc (Ubuntu 4.8.2-19ubuntu1) 4.8.2和一个3.13.0-52的linux内核编译w / gcc 4.8.2


编辑 :我做了两个程序strace ,这里是重要的一部分:

outputfopen(“/ dev / stdout”,“w”) )没有fflush(stdout)scheme,产生:

 ... open("/dev/stdout", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f62f21e9000 write(3, "!", 1!) = 1 write(1, "Hello, World!", 13Hello, World!) = 13 exit_group(0) = ? 

使用fflush(stdout)产生并执行正确的命令:

 ... open("/dev/stdout", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 write(1, "Hello, World!", 13Hello, World!) = 13 fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5ad4557000 write(3, "!", 1!) = 1 exit_group(0) = ? 

stdout来自stdlib.h )场景产生:

 ... write(1, "Hello, World!!", 14Hello, World!!) = 14 exit_group(0) = ? 

所以看起来FILE * output = fopen("/dev/stdout")stream使用与stdout不同的文件描述符同样, printf使用stdout如此第三种情况下,string在被推送到stream之前被汇编。

这两个流( stdoutoutput )都被缓冲。 没有任何东西被写入,直到它们被刷新。 既然你没有明确地冲洗它们,也没有安排它们被自动冲洗,它们只在被关闭时才被自动冲洗。

你也没有明确地关闭它们,所以它们被标准库的on_exit钩子关闭(和刷新)。 正如William Pursell正确指出的那样,缓冲的I / O流关闭的顺序没有被指定。

查看fflush(3)fclose(3)setbuf(3)手册页以获取有关控制何时以及如何刷新输出的更多信息。

/dev/stdout不同于/proc/self/fd/0 。 事实上,如果你没有足够的权限,你将无法写入/dev/stdout因为/dev/stdout不是Linux中的任何标准字符设备,任何试图用"w"选项打开它的尝试都会尝试在该目录上创建一个实际的常规文件。 你正在寻找的字符设备是/dev/tty

在C语言中, stdoutFILE *类型的初始化全局变量,它指向标准输出文件,即描述符为1的文件stdout只存在于C命名空间中,并且不与任何名为"stdout"