c - FILE * "/dev/stdout"和 stdout 之间的区别

标签 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!

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

Hello, World!!

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

这个行为更有趣,因为它不会覆盖“Hello”的第一个字符,而是将自己插入行缓冲区的第一个位置,位于已插入的字符串之前。

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

谁能解释一下这里到底发生了什么?


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


编辑:我已经对这两个程序进行了strace,这里是重要的部分:

输出 (fopen("/dev/stdout", "w")) 没有 fflush(stdout) 场景产生:

...
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 因此,在第三种情况下,字符串在被推送到流上之前被组装。

最佳答案

两个流(stdoutoutput)都被缓冲了。在它们被刷新之前,实际上没有任何内容被写入。由于您没有明确地刷新它们,也没有安排它们自动刷新,因此它们只会在关闭时自动刷新。

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

查看 fflush(3)fclose(3)setbuf(3) 手册页,了解有关控制时间和时间的更多信息你的输出是如何刷新的。

关于c - FILE * "/dev/stdout"和 stdout 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30325508/

相关文章:

linux - rdiff-backup fatal error ,找到相关的增量?

c - 在哪里可以找到我的系统对标准 C 库函数的实现?

c - Solaris 11/Illumos/OmniOS : Which package has/usr/include/sys/types. h?

c - 标签作为内联汇编宏中的值

c++ - 32位整数中set bits的计数方法说明

c - 可能包含哪些文件?

linux - 暂时停止 Qt5/QML 更新帧缓冲区 (/dev/fb0)

c - 移动字符串数组中的元素并用零填充

Python 返回 "SyntaxError: invalid syntax sys module"

c - 为什么 fseek 使用 read() 系统调用?