FILE *"/dev/stdout"之间的区别和标准输出 [英] Difference between FILE * "/dev/stdout" and stdout

查看:128
本文介绍了FILE *"/dev/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文件描述符进行编译时,输出为:

When compiled using the output file descriptor the output is:

!Hello, World!

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

when compiled using the stdout file descriptor provided by stdio.h the output is as expected:

Hello, World!!

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

I figure when calling putc with the latter, it will print directly to the stdout and when using the file descriptor on /dev/stdout it will open a pipe and print into that. I'm not certain though.

该行为更加有趣,因为它不会覆盖"Hello"的第一个字符,而是将自身推入行缓冲区中位于已推入字符串前面的第一个位置.

The behavior is even more interesting, as it does not overwrite the first character of the 'Hello' but rather pushes itself into the first position of the line buffer in front of the already pushed string.

从逻辑的角度来看,这是安静而出乎意料的.

From a logical point of view this is quiet unexpected.

任何人都可以解释这里到底发生了什么吗?

Can anyone explain what exactly is going on here?

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

I'm using cc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 and a 3.13.0-52 linux kernel compiled w/ gcc 4.8.2

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

Edit: I've done an strace of both programs, and here is the important part:

没有fflush(stdout)方案的output( fopen("/dev/stdout","w"))产生:

...
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)会产生并强制执行正确的顺序:

using fflush(stdout) produces and enforces correct order:

...
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 的)场景产生:

The stdout (from stdlib.h) scenario produces:

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

因此,看来FILE * output = fopen("/dev/stdout")流使用的文件描述符与stdout不同 同样,似乎printf使用stdout 因此,在第三种情况下,在将字符串推入流之前先对其进行组装.

So it seems the FILE * output = fopen("/dev/stdout") stream uses a different file descriptor than stdout Also as it seems printf uses stdout Thus in the third scenario the string is assembled before it is pushed on the stream.

推荐答案

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

Both of the streams (stdout and output) are buffered. Nothing actually gets written until they are flushed. Since you are not explicitly flushing them, nor arranging for them to be automatically flushed, they are only being auto-flushed when they are closed.

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

You are also not explicitly closing them, so they're being closed (and flushed) by the standard library's on_exit hooks. And as William Pursell correctly pointed out, the order in which the buffered I/O streams are closed is not specified.

请参阅fflush(3)fclose(3)setbuf(3)手册页,以获取有关控制何时以及如何刷新输出的更多信息.

Look at fflush(3), fclose(3), and setbuf(3) manual pages for more information on controlling when and how your output gets flushed.

这篇关于FILE *"/dev/stdout"之间的区别和标准输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆