写入文件时,C程序以错误的顺序输出文本

时间:2023-01-06 01:41:00

I have a C program that compiles to an executable called myprogram. This is its main function:

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

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

When I run myprogram > output.txt in a Linux shell and then examine output.txt, I see the output of ls listed above "this is a test message."

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

I feel like it should be the other way around. Why is this happening, and what can I do so that "this is a test message" appears at the top of output.txt?

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

If it matters, I'm new to both C and working in a command line.

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

3 个解决方案

#1


84  

By default output to stdout is line-buffered when connected to a terminal. That is, the buffer is flushed when it's full or when you add a newline.

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

However, if stdout is not connected to a terminal, like what happens when you redirect the output from your program to a file, then stdout becomes fully buffered. That means the buffer will be flushed and actually written either when it's full or when explicitly flushed (which happens when the program exits).

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

This means that the output of a separate process started from your code (like what happens when you call system) will most likely be written first, since the buffer of that process will be flushed when that process ends, which is before your own process.

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

What happens when using redirection (or pipes for that matter):

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

  1. Your printf call writes to the stdout buffer.
  2. 您的printf调用写入stdout缓冲区。

  3. The system function starts a new process, which writes to its own buffer.
  4. 系统函数启动一个新进程,该进程写入自己的缓冲区。

  5. When the external process (started by your system call) exits, its buffer is flushed and written. Your own buffer in your own process, isn't touched.
  6. 当外部进程(由系统调用启动)退出时,将刷新并写入其缓冲区。您自己的进程中自己的缓冲区未被触及。

  7. Your own process ends, and your stdout buffer is flushed and written.
  8. 您自己的进程结束,您的stdout缓冲区被刷新并写入。

To get the output in the "correct" (or at least expected) order, call fflush before calling system, to explicitly flush stdout.

要以“正确”(或至少预期)的顺序获取输出,请在调用system之前调用fflush,以显式刷新stdout。

#2


12  

It is related to output buffering. I managed to reproduce the same behaviour. Forcing the flush did it for me.

它与输出缓冲有关。我设法重现了相同的行为。迫使冲洗为我做了。

#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;}

Before adding the fflush:

在添加fflush之前:

$ ./main > foo$ cat foomainmain.cthis is a test message.

and after:

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

#3


5  

I suspect it's because of the order in which the stdout buffer gets flushed, which is not necessarily deterministic. It's possible that the parent spawns the ls process and doesn't flush its own stdout until after that returns. It may not actually flush stdout until the process exits.

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

Try adding fflush (stdout) after the printf statement and see if that forces the output to appear first.

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

#1


84  

By default output to stdout is line-buffered when connected to a terminal. That is, the buffer is flushed when it's full or when you add a newline.

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

However, if stdout is not connected to a terminal, like what happens when you redirect the output from your program to a file, then stdout becomes fully buffered. That means the buffer will be flushed and actually written either when it's full or when explicitly flushed (which happens when the program exits).

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

This means that the output of a separate process started from your code (like what happens when you call system) will most likely be written first, since the buffer of that process will be flushed when that process ends, which is before your own process.

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

What happens when using redirection (or pipes for that matter):

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

  1. Your printf call writes to the stdout buffer.
  2. 您的printf调用写入stdout缓冲区。

  3. The system function starts a new process, which writes to its own buffer.
  4. 系统函数启动一个新进程,该进程写入自己的缓冲区。

  5. When the external process (started by your system call) exits, its buffer is flushed and written. Your own buffer in your own process, isn't touched.
  6. 当外部进程(由系统调用启动)退出时,将刷新并写入其缓冲区。您自己的进程中自己的缓冲区未被触及。

  7. Your own process ends, and your stdout buffer is flushed and written.
  8. 您自己的进程结束,您的stdout缓冲区被刷新并写入。

To get the output in the "correct" (or at least expected) order, call fflush before calling system, to explicitly flush stdout.

要以“正确”(或至少预期)的顺序获取输出,请在调用system之前调用fflush,以显式刷新stdout。

#2


12  

It is related to output buffering. I managed to reproduce the same behaviour. Forcing the flush did it for me.

它与输出缓冲有关。我设法重现了相同的行为。迫使冲洗为我做了。

#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;}

Before adding the fflush:

在添加fflush之前:

$ ./main > foo$ cat foomainmain.cthis is a test message.

and after:

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

#3


5  

I suspect it's because of the order in which the stdout buffer gets flushed, which is not necessarily deterministic. It's possible that the parent spawns the ls process and doesn't flush its own stdout until after that returns. It may not actually flush stdout until the process exits.

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

Try adding fflush (stdout) after the printf statement and see if that forces the output to appear first.

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