改行がフォーマット文字列に含まれていないと、呼び出し後にprintf
がフラッシュしないのはなぜですか?このPOSIXの動作はありますか?毎回printf
がすぐにフラッシュするようにするにはどうすればよいですか?
stdout
ストリームはバッファリングされているので、改行に達した後(または指示されたとき)にのみバッファ内にあるものを表示します。すぐに印刷する方法がいくつかあります。
代わりにfprintf
を使ってstderrに出力します。
fprintf(stderr, "I will be printed immediately");
fflush
を使用する必要があるときはいつでも標準出力をフラッシュしてください。
printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer
編集 :以下のAndy Rossのコメントから、setbuf
を使って標準出力のバッファリングを無効にすることもできます。
setbuf(stdout, NULL);
いいえ、それはPOSIXの動作ではなく、ISOの動作です(まあ、それは は POSIXの動作ですが、ISOに準拠している場合のみ)。
標準出力は、対話型デバイスを参照していることが検出できる場合はラインバッファリングされ、それ以外の場合は完全バッファリングされます。そのため、改行を送ってもprintf
がフラッシュしない状況があります。例えば:
myprog >myfile.txt
ユーザーと対話しているのであれば、おそらくすべての行を見たいと思うので、これは効率性にとって意味があります。出力をファイルに送信している場合は、相手側にユーザーがいない可能性が最も高いです(不可能ではありませんが、ファイルの最後尾になる可能性があります)。 は - ユーザーがすべての文字を見たいと主張しているが、それには2つの問題があります。
1つは、あまり効率的ではないということです。 2つ目は、元のANSI Cの使命は、invent new behaviorではなく、主に existing behaviorをコード化することであり、これらの設計決定はANSIがプロセスを開始するずっと前に行われました。現在でもISOでも、規格内の既存の規則を変更するときには非常に慎重に取り組んでいます。
どのように対処するかに関しては、あなたがすぐに見たいと思うあらゆる出力呼び出しの後にfflush (stdout)
を行うなら、それは問題を解決するでしょう。
別の方法として、setvbuf
を操作する前にstdout
を使用してバッファなしに設定することもできます。そうすれば、これらのfflush
行すべてをコードに追加することを心配する必要がなくなります。
setvbuf (stdout, NULL, _IONBF, BUFSIZ);
are でファイルに出力を送信すると、パフォーマンスにかなりの影響を及ぼす可能性があることに注意してください。また、これに対するサポートは実装定義であり、規格によって保証されていないことにも注意してください。
ISO C99のセクション7.19.3/3
は関連するビットです。
ストリームが バッファなし の場合、文字はできるだけ早くソースからまたは宛先に表示されることを意図しています。そうでなければ、文字は累積され、ブロックとしてホスト環境との間で送受信される可能性があります。
ストリームが 完全にバッファされた の場合、文字は、バッファがいっぱいになったときにブロックとしてホスト環境との間で送受信されることを意図しています。
ストリームが line buffered の場合、文字は改行文字が検出されたときにブロックとしてホスト環境との間で送受信されることを意図しています。
さらに、文字は、バッファーがいっぱいになったとき、バッファリングされていないストリームで入力が要求されたとき、またはホスト環境からの文字の送信を必要とするラインバッファー付きストリームで入力が要求されたときに、ホスト環境にブロックとして送信されます。 。
これらの特性のサポートは実装定義であり、
setbuf
およびsetvbuf
関数を介して影響を受ける可能性があります。
これはおそらく効率のためであり、単一のTTYに複数のプログラムを書き込む場合はこの方法で行の文字がインターレースされないためです。そのため、プログラムAとBが出力している場合、通常は次のようになります。
program A output
program B output
program B output
program A output
program B output
これは臭いが、それはよりも優れています
proprogrgraam m AB ououtputputt
prproogrgram amB A ououtputtput
program B output
改行でフラッシュすることは保証されていないことに注意してください。したがって、フラッシュが問題になる場合は、明示的にフラッシュする必要があります。
すぐにフラッシュするにはfflush(stdout)
またはfflush(NULL)
を呼び出します(NULL
はすべてをフラッシュすることを意味します)。
注:Microsoftランタイムライブラリはラインバッファリングをサポートしていないので、printf("will print immediatelly to terminal")
:
stdoutはバッファされているので、改行が表示された後にのみ出力されます。
すぐに出力するには、次のいずれかを行います。
デフォルトでは、stdoutは行バッファ、stderrはバッファなし、fileは完全バッファです。
代わりに、バッファなしのstderrにfprintfすることができます。また、必要に応じて標準出力をフラッシュすることもできます。あるいは、stdoutをunbufferedに設定することもできます。
バッファリングを無効にするにはsetbuf(stdout, NULL);
を使います。
通常、バッファリングには2つのレベルがあります。
1。カーネルバッファーキャッシュ(読み取り/書き込みの高速化)
2。I/Oライブラリのバッファリング(システムコールの数を減らす)
fprintf and write()
の例を見てみましょう。
fprintf()
を呼び出すと、ファイルに直接書き込まれません。最初にプログラムのメモリのstdioバッファに移動します。そこから、書き込みシステムコールを使用してカーネルバッファキャッシュに書き込まれます。したがって、I/Oバッファーをスキップする1つの方法は、直接write()を使用することです。他の方法は、setbuff(stream,NULL)
を使用することです。これにより、バッファリングモードがバッファリングなしに設定され、データがカーネルバッファに直接書き込まれます。データをカーネルバッファーに強制的にシフトするには、「\ n」を使用できます。これは、デフォルトのバッファリングモードが「ラインバッファリング」の場合、I/Oバッファーをフラッシュします。または、fflush(FILE *stream)
を使用できます。
これでカーネルバッファーになりました。 Kernel(/ OS)はディスクアクセス時間を最小限に抑えたいため、ディスクのブロックのみを読み書きします。したがって、read()
が発行されると、これはシステムコールであり、直接またはfscanf()
を介して呼び出すことができ、カーネルはディスクからディスクブロックを読み取り、バッファーに格納します。そのデータは、ここからユーザースペースにコピーされます。
同様に、I/Oバッファーから受信したfprintf()
データは、カーネルによってディスクに書き込まれます。これにより、read()write()が高速になります。
カーネルにwrite()
を強制的に開始させ、その後、データ転送がハードウェアコントローラーによって制御されるようにするには、いくつかの方法もあります。書き込み呼び出し中にO_SYNC
または同様のフラグを使用できます。または、fsync(),fdatasync(),sync()
などの他の関数を使用して、カーネルバッファーでデータが利用可能になるとすぐにカーネルが書き込みを開始するようにすることもできます。