Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将输出重定向到文件时,printf()和system()的结果顺序错误_C_Linux_Printf_Child Process_Io Redirection - Fatal编程技术网

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

C 将输出重定向到文件时,printf()和system()的结果顺序错误,c,linux,printf,child-process,io-redirection,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; } 当我在Linux shell中运行myprogram>output.txt并检查output.txt时,我看到上面列出的ls的输出“这是一条测试消息” 我觉得应该是另一种方式。为什么会发生这种情况,我该

我有一个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
的输出“这是一条测试消息”

我觉得应该是另一种方式。为什么会发生这种情况,我该怎么做才能使“这是一条测试消息”出现在output.txt的顶部


如果有关系的话,我对C和命令行都是新手。

我怀疑这是因为标准输出缓冲区刷新的顺序,这不一定是确定的。父进程可能会生成
ls
进程,直到返回后才刷新自己的标准输出。在进程退出之前,它可能不会实际刷新标准输出


尝试在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;
}
及之后:

$ ./main > foo
$ cat foo
this is a test message.
foo
main
main.c

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

但是,如果
stdout
未连接到终端,如将程序输出重定向到文件时所发生的情况,则
stdout
将被完全缓冲。这意味着当缓冲区已满或显式刷新(程序退出时发生)时,缓冲区将被刷新并实际写入

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

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

  • 您的
    printf
    调用将写入
    stdout
    缓冲区
  • system
    函数启动一个新进程,该进程将写入自己的缓冲区
  • 当外部进程(由
    系统
    调用启动)退出时,将刷新并写入其缓冲区。在您自己的流程中,您自己的缓冲区不会被触及
  • 您自己的进程结束,您的
    stdout
    缓冲区被刷新和写入

  • 要以“正确”(或至少预期)的顺序获得输出,请在调用
    system
    之前调用,以显式刷新
    stdout
    ,或在任何输出之前调用以完全禁用缓冲。

    出于好奇:即使在
    system
    之后调用
    fflush
    ,程序输出是否正确,或者
    系统
    在该调用中执行所有操作(包括它自己的
    fflush
    )?另一个奇怪的问题是
    system()
    的输出不也会在以前使用的
    stdout
    缓冲区中结束吗?毕竟,它并没有绕过它直接写入控制台。这两个程序的
    stdout
    s都是链接的,这一点很明显,因为它们都在
    output.txt
    @Vilx-,不,
    stdio
    是一个库,它使用的缓冲区存在于进程的内存中
    system()
    使用单独的内存空间启动新进程,从而使用单独的缓冲区。但是,子进程确实从父进程继承了文件描述符,这就是为什么输出会转到同一个文件。操作系统级文件描述符与
    write()
    系统调用之间的差异;C库
    文件
    流和
    printf()
    (等)在这里很重要。您的答案掩盖了OP可能应该注意的一个细节:C程序中的
    stdout
    变量包含指向libc
    文件
    对象的指针,但这两个进程共享的是一个开放的文件描述符。当您混合使用不同的输出和输入缓冲区,但不必刷新输出时,无法保证它们的写入顺序。您的<代码> Prtff<代码>输出可以在<>代码> L< <代码>输出中间写入,输出!当然,输出在其他输出中间的输出是罕见的,但是我看到了它的发生。直观地说,你认为“一条输出线无法在另一条线中间写出”,但是当你真的看到它发生时,你对现实的感知就受到了挑战。你需要冲洗打印出来的东西才能立即打印出来。
    $ ./main > foo
    $ cat foo
    this is a test message.
    foo
    main
    main.c