我们来看看这个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;
}
Run Code Online (Sandbox Code Playgroud)
使用output文件描述符编译时,输出为:
!Hello, World!
Run Code Online (Sandbox Code Playgroud)
使用输出stdout提供的文件描述符编译时stdio.h是按预期方式:
Hello, World!!
Run Code Online (Sandbox Code Playgroud)
我想,当putc用后者调用时,它会直接打印到stdout,当使用文件描述符时/dev/stdout,它将打开一个管道并打印到其中.我不确定.
这种行为更有趣,因为它不会覆盖'Hello'的第一个字符,而是将自己推入已经推送的字符串前面的行缓冲区的第一个位置.
从逻辑的角度来看,这是非常意外的.
谁能解释一下究竟发生了什么?
我正在使用
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)会产生:
...
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) = ?
Run Code Online (Sandbox Code Playgroud)
使用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) = ?
Run Code Online (Sandbox Code Playgroud)
的stdout(stdlib.h中)业务情景生产:
...
write(1, "Hello, World!!", 14Hello, World!!) = 14
exit_group(0) = ?
Run Code Online (Sandbox Code Playgroud)
因此,它似乎FILE * output = fopen("/dev/stdout")流比使用一个不同的文件描述符stdout
此外,因为它似乎printf使用stdout
的第三种情况是在流推前串组装这样.
Gil*_*ton 18
两个流(stdout和output)都被缓冲.在刷新之前,实际上什么都没有写入.由于您没有明确地刷新它们,也没有安排它们被自动刷新,因此它们仅在关闭时自动刷新.
你也没有明确地关闭它们,所以它们被标准库的on_exit钩子关闭(并刷新).正如William Pursell正确指出的那样,未指定缓冲I/O流关闭的顺序.
看看fflush(3),fclose(3)和setbuf(3)手册页的详细信息,控制何时以及如何你的输出被刷新.