当输出重定向到文件时,printf() 和 system() 的结果顺序错误
Results of printf() and system() are in the wrong order when output is redirected to a file
我有一个 C 程序可以编译成一个名为 myprogram 的可执行文件。这是它的主要功能:
int main(int argc, char ** argv) {
printf("this is a test message.\n");
system("ls");
return 0;
}
当我在 Linux shell 中 运行 myprogram > output.txt
然后检查 output.txt 时,我看到上面列出的 ls
的输出"this is a test message."
我觉得应该反过来。为什么会这样,我该怎么做才能让 "this is a test message" 出现在 output.txt 的顶部?
如果重要的话,我是 C 和命令行工作的新手。
我怀疑这是因为 stdout 缓冲区被刷新的顺序,这不一定是确定的。父进程可能会生成 ls
进程,并且直到 returns 之后才刷新自己的标准输出。在进程退出之前,它可能不会真正刷新标准输出。
尝试在 printf 语句后添加 fflush (stdout)
,看看是否强制输出先出现。
与输出缓冲有关。我设法重现了相同的行为。强制同花顺对我有用。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
printf("this is a test message.\n");
fflush(stdout);
system("ls");
return 0;
}
在添加 fflush 之前:
$ ./main > foo
$ cat foo
main
main.c
this is a test message.
及之后:
$ ./main > foo
$ cat foo
this is a test message.
foo
main
main.c
默认情况下,当连接到终端时,stdout
的输出是 行缓冲 。也就是说,当缓冲区已满或添加换行符时,缓冲区会被刷新。
但是,如果 stdout
没有连接到终端,就像你重定向输出时发生的情况程序到文件,然后 stdout
变为 完全缓冲 。这意味着缓冲区将被刷新并在缓冲区已满或显式刷新时实际写入(程序退出时发生)。
这意味着从您的代码开始的单独进程的输出(就像您调用 system
时发生的情况)很可能首先被写入,因为该进程的缓冲区将在该进程时被刷新结束,这是在你自己的过程之前。
使用重定向(或管道)时会发生什么:
- 您的
printf
调用写入 stdout
缓冲区。
system
函数启动一个新进程,写入自己的缓冲区。
- 当外部进程(由您的
system
调用启动)退出时,其缓冲区将被刷新并写入。您自己进程中的缓冲区未被触及。
- 您自己的进程结束,您的
stdout
缓冲区被刷新并写入。
要获得 "correct"(或至少预期)顺序的输出,请在任何输出之前调用 fflush
before calling system
, to explicitly flush stdout
, or call setbuf
以完全禁用缓冲。
我有一个 C 程序可以编译成一个名为 myprogram 的可执行文件。这是它的主要功能:
int main(int argc, char ** argv) {
printf("this is a test message.\n");
system("ls");
return 0;
}
当我在 Linux shell 中 运行 myprogram > output.txt
然后检查 output.txt 时,我看到上面列出的 ls
的输出"this is a test message."
我觉得应该反过来。为什么会这样,我该怎么做才能让 "this is a test message" 出现在 output.txt 的顶部?
如果重要的话,我是 C 和命令行工作的新手。
我怀疑这是因为 stdout 缓冲区被刷新的顺序,这不一定是确定的。父进程可能会生成 ls
进程,并且直到 returns 之后才刷新自己的标准输出。在进程退出之前,它可能不会真正刷新标准输出。
尝试在 printf 语句后添加 fflush (stdout)
,看看是否强制输出先出现。
与输出缓冲有关。我设法重现了相同的行为。强制同花顺对我有用。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
printf("this is a test message.\n");
fflush(stdout);
system("ls");
return 0;
}
在添加 fflush 之前:
$ ./main > foo
$ cat foo
main
main.c
this is a test message.
及之后:
$ ./main > foo
$ cat foo
this is a test message.
foo
main
main.c
默认情况下,当连接到终端时,stdout
的输出是 行缓冲 。也就是说,当缓冲区已满或添加换行符时,缓冲区会被刷新。
但是,如果 stdout
没有连接到终端,就像你重定向输出时发生的情况程序到文件,然后 stdout
变为 完全缓冲 。这意味着缓冲区将被刷新并在缓冲区已满或显式刷新时实际写入(程序退出时发生)。
这意味着从您的代码开始的单独进程的输出(就像您调用 system
时发生的情况)很可能首先被写入,因为该进程的缓冲区将在该进程时被刷新结束,这是在你自己的过程之前。
使用重定向(或管道)时会发生什么:
- 您的
printf
调用写入stdout
缓冲区。 system
函数启动一个新进程,写入自己的缓冲区。- 当外部进程(由您的
system
调用启动)退出时,其缓冲区将被刷新并写入。您自己进程中的缓冲区未被触及。 - 您自己的进程结束,您的
stdout
缓冲区被刷新并写入。
要获得 "correct"(或至少预期)顺序的输出,请在任何输出之前调用 fflush
before calling system
, to explicitly flush stdout
, or call setbuf
以完全禁用缓冲。