web-dev-qa-db-ja.com

出力がファイルにリダイレクトされると、printf()とsystem()の結果が間違った順序になる

Myprogramという実行可能ファイルにコンパイルするCプログラムがあります。これがその主な機能です。

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

  return 0;
}

Linuxシェルでmyprogram > output.txtを実行してからoutput.txtを調べると、上記の「これはテストメッセージです」のlsの出力が表示されます。

私はそれが逆であるべきだと感じます。なぜこれが起こっているのでしょうか、そしてoutput.txtの先頭に「これはテストメッセージです」と表示されるようにするにはどうすればよいですか。

それが問題であるならば、私はCとコマンドラインで働くことの両方に新しいです。

97
Archr

stdoutへのデフォルトの出力は、端末に接続された時にラインバッファされたです。つまり、バッファはいっぱいになったときや改行を追加したときにフラッシュされます。

ただし、stdoutが端末に接続されていない場合は、になります。プログラムをファイルに変換すると、stdout完全バッファになります。つまり、バッファがいっぱいになったとき、または明示的にフラッシュされたとき(プログラムの終了時に発生)に、バッファがフラッシュされて実際に書き込まれます。

つまり、systemを呼び出したときの処理のように、コードから開始された別のプロセスの出力が最初に書き込まれることになります。これは、そのプロセスのバッファがそのプロセスの終了時にフラッシュされるためです。

リダイレクション(またはそのことについてはパイプ)を使用するとどうなりますか。

  1. printf呼び出しはstdoutバッファに書き込みます。
  2. system関数は新しいプロセスを開始し、それがそれ自身のバッファに書き込みます。
  3. system呼び出しによって開始された)外部プロセスが終了すると、そのバッファはフラッシュされ書き込まれます。あなた自身のプロセスにおけるあなた自身のバッファは、触れられていません。
  4. あなた自身のプロセスは終了し、あなたのstdoutバッファはフラッシュされ書き込まれます。

「正しい」(または少なくとも期待される)順序で出力を取得するには、fflushを呼び出す前に system を呼び出して明示的にstdoutをフラッシュするか、無効にする出力の前に setbuf を呼び出します。完全にバッファリングします。

142

出力バッファリングに関連しています。私はなんとか同じ振る舞いを再現しました。フラッシュを強制することは私のためにそれをしました。

#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
18
Aif

これは、標準出力バッファがフラッシュされる順序が原因であると考えられます。これは必ずしも確定的ではありません。親がlsプロセスを起動し、それが戻るまで独自の標準出力をフラッシュしないことが可能です。プロセスが終了するまで、実際には標準出力をフラッシュしないかもしれません。

Printfステートメントの後にfflush (stdout)を追加して、出力が最初に表示されるようにするかどうかを確認してください。