让我们来看看这个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
,这里是重要的一部分:
output
( fopen(“/ 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之前被汇编。
这两个流( stdout
和output
)都被缓冲。 没有任何东西被写入,直到它们被刷新。 既然你没有明确地冲洗它们,也没有安排它们被自动冲洗,它们只在被关闭时才被自动冲洗。
你也没有明确地关闭它们,所以它们被标准库的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语言中, stdout
是FILE *
类型的初始化全局变量,它指向标准输出文件,即描述符为1的文件stdout
只存在于C命名空间中,并且不与任何名为"stdout"