当输出重定向到文件时,printf()和system()的结果顺序错误

Arc*_*chr 98 c linux printf child-process io-redirection

我有一个C程序编译成一个名为myprogram的可执行文件.这是它的主要功能:

int main(int argc, char ** argv) {
  printf("this is a test message.\n");
  system("ls");

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我myprogram > output.txt在Linux shell中运行然后检查output.txt时,我看到ls上面列出的输出"这是一条测试消息".

我觉得应该是相反的方式.为什么会发生这种情况,我能做些什么,以便"这是一条测试消息"出现在output.txt的顶部?

如果重要的话,我是C的新手并且在命令行中工作.

Som*_*ude 143

默认情况下,当连接到终端时,输出stdout线路缓冲.也就是说,当缓冲区已满或添加换行符时刷新缓冲区.

但是,如果stdout没有连接到终端,就像当你重定向从程序到文件的输出会发生什么,然后stdout变成全缓冲.这意味着缓冲区将被刷新并在其已满或明确刷新时实际写入(当程序退出时会发生).

这意味着从您的代码开始的单独进程的输出(就像您调用时发生的那样system)很可能首先被写入,因为该进程的缓冲区将在该进程结束时刷新,这在您自己的进程之前.

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

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

要以"正确"(或至少预期)的顺序获取输出,请fflush在调用之前调用system,显式刷新stdout,或setbuf在任何输出之前调用以完全禁用缓冲.

  • @ Vilx-,不,`stdio`是一个库,它使用的缓冲区存在于进程的内存中.`system()`启动一个具有单独内存空间的新进程,因此单独的缓冲区.但子进程确实从父进程继承了文件描述符,这就是输出转到同一文件的原因.OS级文件描述符和`write()`系统调用之间的区别; 而C库`FILE`流和`printf()`(等)在这里很重要. (12认同)
  • 你的回答掩盖了OP应该注意的一个细节:C程序中的`stdout` _variable_包含一个指向libc`FILE`对象的指针,但是这两个进程共享的是一个open _file描述符_. (4认同)

Aif*_*Aif 18

它与输出缓冲有关.我设法重现了同样的行为.强迫冲洗为我做了.

#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;
}
Run Code Online (Sandbox Code Playgroud)

在添加fflush之前:

$ ./main > foo
$ cat foo
main
main.c
this is a test message.
Run Code Online (Sandbox Code Playgroud)

之后:

$ ./main > foo
$ cat foo
this is a test message.
foo
main
main.c
Run Code Online (Sandbox Code Playgroud)


Con*_*lls 7

我怀疑这是因为stdout缓冲区被刷新的顺序,这不一定是确定性的.父ls进程可能会生成进程,并且在返回之前不会刷新自己的stdout.在进程退出之前,它可能实际上不会刷新stdout.

尝试fflush (stdout)在printf语句后添加,看看是否强制输出首先出现.


归档时间:

查看次数:

4834 次

最近记录:

7 年 前