FILE *" / dev / stdout"之间的区别和标准输出

时间:2015-05-19 12:22:02

标签: c linux libc

让我们来看看 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!

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

Hello, World!!

我想用后者调用putc时会直接将打印stdout,并且在/dev/stdout上使用文件描述符时会打开一个管道并打印到其中。我不确定。

这种行为更有趣,因为它不会覆盖“你好”的第一个字符。而是将自己推入已经推动的字符串前面的行缓冲区的第一个位置。

从逻辑的角度来看,这是出乎意料的。

有人能解释一下究竟发生了什么吗?

我正在使用 cc (Ubuntu 4.8.2-19ubuntu1) 4.8.2和3.13.0-52 linux内核编译w / gcc 4.8.2

修改:我已经完成了strace这两个程序,这是重要的部分:

没有output方案的fflush(stdout) fopen(&#34; / dev / stdout&#34;,&#34; w&#34;))会产生:

...
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")流使用的文件描述符与stdout不同 此外,似乎printf使用stdout 因此,在第三种情况下,字符串在被推送到流之前被组装。

2 个答案:

答案 0 :(得分:18)

两个流(stdoutoutput)都是缓冲的。在刷新之前,实际上什么都没有写入。由于您没有明确地刷新它们,也没有安排它们被自动刷新,因此它们仅在关闭时自动刷新。

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

查看fflush(3)fclose(3)setbuf(3)手册页,了解有关控制输出何时以及如何刷新的详细信息。

答案 1 :(得分:2)

/dev/stdout/proc/self/fd/0不同。事实上,如果你没有足够的权限,你将无法写入/dev/stdout,因为/dev/stdout不是Linux中的任何标准字符设备,并且任何尝试使用{{1}来强制它}选项将尝试在该目录上创建一个实际的常规文件。您要查找的角色设备是"w"

在C语言中,/dev/tty是类型stdout的初始化全局变量,它指向标准输出文件,即描述符为1的文件。FILE *仅存在于C命名空间,与名为stdout

的任何实际文件无关