当输出被重定向到一个文件时,printf()和system()的结果顺序会出错。

7 浏览
0 Comments

当输出被重定向到一个文件时,printf()和system()的结果顺序会出错。

这个问题已经有了答案:

为什么write()在输出重定向中在printf()之前打印?

为什么printf在调用后不会刷新,除非格式字符串中有一个新行符?

我有一个编译成可执行文件名为myprogram的C程序,这是它的主函数:

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,也不熟悉在命令行中工作。

admin 更改状态以发布 2023年5月23日
0
0 Comments

这与输出缓冲有关。我成功地复制了相同的行为。强制刷新对我有用。

#include 
#include 
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

0
0 Comments

默认情况下,当连接到终端时,对于stdout的输出是按行缓冲。也就是说,当缓冲区满或添加换行符时,缓冲区将被刷新。

然而,如果stdout没有连接到终端,比如将程序的输出重定向到文件时,那么stdout将变成完全缓冲的。也就是说,缓冲区将被刷新并且实际上会在缓冲区满或显式刷新时写入(发生在程序退出时)。

这意味着从你的代码启动的一个单独的进程的输出(例如当你调用system时发生的情况)很可能首先被写入,因为在该进程结束时,该进程的缓冲区将被刷新,而在你自己的进程之前。

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

  1. 你的printf调用写入stdout缓冲区。
  2. system函数启动一个新的进程,该进程写入自己的缓冲区。
  3. 当外部进程(由你的system调用启动的进程)退出时,它的缓冲区将被刷新和写入。你自己进程中的缓冲区不会被处理。
  4. 你自己的进程结束,你的stdout缓冲区被刷新并写入。

为了按照“正确的”(或至少是预期的)顺序获取输出,请在调用system之前调用fflush,以显式刷新stdout,或在任何输出之前调用setbuf以完全禁用缓冲。

0