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とコマンドラインで働くことの両方に新しいです。
stdout
へのデフォルトの出力は、端末に接続された時にラインバッファされたです。つまり、バッファはいっぱいになったときや改行を追加したときにフラッシュされます。
ただし、stdout
が端末に接続されていない場合は、になります。プログラムをファイルに変換すると、stdout
は完全バッファになります。つまり、バッファがいっぱいになったとき、または明示的にフラッシュされたとき(プログラムの終了時に発生)に、バッファがフラッシュされて実際に書き込まれます。
つまり、system
を呼び出したときの処理のように、コードから開始された別のプロセスの出力が最初に書き込まれることになります。これは、そのプロセスのバッファがそのプロセスの終了時にフラッシュされるためです。
リダイレクション(またはそのことについてはパイプ)を使用するとどうなりますか。
printf
呼び出しはstdout
バッファに書き込みます。system
関数は新しいプロセスを開始し、それがそれ自身のバッファに書き込みます。system
呼び出しによって開始された)外部プロセスが終了すると、そのバッファはフラッシュされ書き込まれます。あなた自身のプロセスにおけるあなた自身のバッファは、触れられていません。stdout
バッファはフラッシュされ書き込まれます。「正しい」(または少なくとも期待される)順序で出力を取得するには、fflush
を呼び出す前に system
を呼び出して明示的にstdout
をフラッシュするか、無効にする出力の前に setbuf
を呼び出します。完全にバッファリングします。
出力バッファリングに関連しています。私はなんとか同じ振る舞いを再現しました。フラッシュを強制することは私のためにそれをしました。
#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
これは、標準出力バッファがフラッシュされる順序が原因であると考えられます。これは必ずしも確定的ではありません。親がls
プロセスを起動し、それが戻るまで独自の標準出力をフラッシュしないことが可能です。プロセスが終了するまで、実際には標準出力をフラッシュしないかもしれません。
Printfステートメントの後にfflush (stdout)
を追加して、出力が最初に表示されるようにするかどうかを確認してください。