Посмотрим на эту программу 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
он откроет pipe и напечатает на нем. Я не уверен, хотя.
Поведение еще более интересно, так как оно не перезаписывает первый символ "Hello", а скорее вставляет себя в первую позицию буфера строк перед уже нажатой строкой.
С логической точки зрения это неожиданно неожиданно.
Кто-нибудь может объяснить, что именно происходит здесь?
Я использую
cc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
и ядро linux 3.13.0-52, скомпилированное 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) = ?
с помощью 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
Таким образом, в третьем сценарии строка собирается до того, как она будет нажата на поток.