以下は、fflush()を使用するためのサンプルコードです。
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <io.h>
void flush(FILE *stream);
int main(void)
{
FILE *stream;
char msg[] = "This is a test";
/* create a file */
stream = fopen("DUMMY.FIL", "w");
/* write some data to the file */
fwrite(msg, strlen(msg), 1, stream);
clrscr();
printf("Press any key to flush DUMMY.FIL:");
getch();
/* flush the data to DUMMY.FIL without closing it */
flush(stream);
printf("\nFile was flushed, Press any key to quit:");
getch();
return 0;
}
void flush(FILE *stream)
{
int duphandle;
/* flush the stream's internal buffer */
fflush(stream);
/* make a duplicate file handle */
duphandle = dup(fileno(stream));
/* close the duplicate handle to flush the DOS buffer */
close(duphandle);
}
私がfflush()について知っているのは、それが出力バッファーをフラッシュするために使用されるライブラリー関数であることだけです。 fflush()を使用する基本的な目的と、それをどこで使用できるかを知りたいです。そして、主に私は知ることに興味がありますfflush()を使用するとどのような問題が発生する可能性がありますか
fflush
の「問題が発生する可能性がある」(過度の)可能性を説明するのは少し難しいです。あらゆる種類のことできる目標やアプローチに応じて、問題になる、または問題になる。おそらくこれをよりよく見る方法は、fflush
の意図です。
最初に考慮すべきことは、fflush
が出力ストリームでのみ定義されていることです。出力ストリームは、「ファイルに書き込むもの」を大きな(ish)バッファーに収集し、そのバッファーをファイルに書き込みます。この収集と書き込みのポイントは、次の2つの方法で速度と効率を向上させることです。
したがって、Cライブラリとそのstdioストリーム実装を提供する人々は、OSで適切なことを何でも行って、「合理的に最適な」ブロックサイズを見つけ、すべての出力をそのサイズのチャンクにまとめます。 (今日、4096、8192、16384、および65536は、多くの場合、適切な値になる傾向がありますが、実際にはOSに依存し、場合によっては基礎となるファイルシステムにも依存します。「大きい」が必ずしも「良い」とは限らないことに注意してください。一度に4ギガバイトのチャンクでデータをストリーミングすると、たとえば64キロバイトのチャンクでストリーミングするよりもパフォーマンスが低下する可能性があります。
しかし、これは問題を引き起こします。日付と時刻のスタンプとメッセージを含むログファイルなどのファイルに書き込んでいて、コードが後でそのファイルへの書き込みを続けるとしますが、今はしばらく一時停止して、ログアナライザーは、ログファイルの現在の内容を読み取ります。 1つのオプションは、fclose
を使用してログファイルを閉じてから、fopen
を使用して再度開き、後でデータを追加することです。ただし、保留中のログメッセージを基盤となるOSファイルにプッシュし、ファイルは開いたままにしておく方が効率的です。それがfflush
が行うことです。
バッファリングも別の問題を引き起こします。あなたのコードにいくつかのバグがあり、時々クラッシュしますが、それがクラッシュするかどうかわかりません。そして、あなたが何かを書いて、thisデータが基礎となるファイルシステムに出て行くことが非常に重要だとしましょう。 fflush
を呼び出して、クラッシュする可能性のある不良コードを呼び出す前に、データをOSにプッシュすることができます。 (これはデバッグに適している場合があります。)
または、Unixライクなシステムを使用していて、fork
システムコールがあるとします。この呼び出しは、ユーザー空間全体を複製します(元のプロセスのクローンを作成します)。 stdioバッファーはユーザー空間にあるため、クローンは、fork
呼び出し時に、元のプロセスが保持していた、まだ書き込まれていない、まだ書き込まれていない同じデータを持っています。ここでも、問題を解決する1つの方法は、fflush
を使用する直前にfork
を使用してバッファーデータをプッシュすることです。 fork
の前にすべてが出ている場合、複製するものはありません。新しいクローンはバッファリングされたデータが存在しないため、バッファリングされたデータを書き込もうとしません。
追加するfflush
- esが多いほど、大きなデータのチャンクを収集するという本来のアイデアを打ち破ることになります。つまり、トレードオフを行っています。大きなチャンクはより効率的ですが、他のいくつかの問題を引き起こしているため、「ここでは効率が低く、単なる効率よりも重要な問題を解決する」という決定をします。 fflush
を呼び出します。
時々問題は単に「ソフトウェアをデバッグする」ことです。その場合、fflush
を繰り返し呼び出す代わりに、setbuf
やsetvbuf
などの関数を使用して、stdioストリームのバッファリング動作を変更できます。これは、多くのfflush
呼び出しを追加するよりも便利です(必要なコード変更は少なく、必要なコード変更もありません-フラグでセットバッファリング呼び出しを制御できます)。そのため、「使用に関する問題」と見なすことができます。 (または過度の使用)fflush
"。
まあ、@ torekの答えはほぼ完璧ですが、それほど正確ではない点が1つあります。
最初に考慮すべきことは、fflushが出力ストリームでのみ定義されることです。
Man fflushによると、fflushはinputストリームでも使用できます。
出力ストリームの場合、fflush()は、ストリームの基になる書き込み関数を介して、指定された出力または更新ストリームのすべてのユーザー空間のバッファーデータを強制的に書き込みます。 入力ストリームの場合、fflush()は、基礎となるファイルからフェッチされたが、アプリケーションによって消費されていない、バッファーに入れられたデータを破棄します。ストリームのオープンステータスは影響を受けません。したがって、入力で使用される場合、fflushはそれを破棄します。
これを説明するデモがあります。
#include<stdio.h>
#define MAXLINE 1024
int main(void) {
char buf[MAXLINE];
printf("Prompt: ");
while (fgets(buf, MAXLINE, stdin) != NULL)
fflush(stdin);
if (fputs(buf, stdout) == EOF)
printf("output err");
exit(0);
}