当输出重定向到文件时,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 时发生的情况)很可能首先被写入,因为该进程的缓冲区将在该进程时被刷新结束,这是在你自己的过程之前。

使用重定向(或管道)时会发生什么:

  1. 您的 printf 调用写入 stdout 缓冲区。
  2. system 函数启动一个新进程,写入自己的缓冲区。
  3. 当外部进程(由您的 system 调用启动)退出时,其缓冲区将被刷新并写入。您自己进程中的缓冲区未被触及。
  4. 您自己的进程结束,您的 stdout 缓冲区被刷新并写入。

要获得 "correct"(或至少预期)顺序的输出,请在任何输出之前调用 fflush before calling system, to explicitly flush stdout, or call setbuf 以完全禁用缓冲。