web-dev-qa-db-ja.com

Cプログラミングでfflush(stdin)は何をしますか?

私はCプログラミングが初めてであり、fflush(stdin)が実際にどのように機能するかを理解しようとしています。

次の例では、fflush(stdin)はすべてのバッファーをクリアしますか、3番目の項目の後に入力されたものをすべてクリアしますか?つまり、ユーザーはアカウント番号、スペース、名前、スペース、残高を入力します。これ以降、ユーザーが入力したものはすべてfflush(stdin)でフラッシュされるというのは本当ですか? stdinは空になりません。

それがwhileループに入り、テキストファイルへの書き込みを開始するからです。

2番目の質問は、Ctrl-Zは、ユーザーに入力を要求するのを停止するようにOSに指示しますか?

printf( "Enter the account name and balance. (separated by spaces)\n" );
  printf( "Enter EOF to end input. (Ctrl-Z)\n" );
  printf( "? " );
  scanf( "%d%s%lf", &account, name, &balance );
  fflush(stdin);

  // write account, name and balance into file with fprintf
  while ( !feof( stdin ) )
  { 
     //fflush(stdin);
     fprintf( cfPtr, "%d %s %.2f\n", account, name, balance );
     printf( "? " );
     scanf( "%d%s%lf", &account, name, &balance );
  }

  fclose( cfPtr );
19
C graphics

これに対する答えは、fflush(stream)は出力ストリームに対してのみ正式に定義されているため、fflush(stdout)はOKですが、fflush(stdin)はそうではないということです。

fflush(stream)の目的は、オペレーティングシステムにバッファを基礎ファイルにフラッシュさせることです。正当な使用例として、生徒は次のようなことをすると「プロンプトが表示されない!」などの問題を抱えることがよくあります。

_printf("Enter a number: ");
_

しかし、彼らはこれがうまくいくことを発見しました:

_printf("Enter a number:\n");
_

もちろん、プロンプトの後に改行が必要ないため、少し問題があります。

これは、stdoutへの出力がOSによってバッファリングされ、デフォルトの動作は(多くの場合)改行が検出されたときに実際に端末に出力を書き込むためだけであるためです。 fflush(stdout)の後にprintf()を追加すると、問題が解決します。

_printf("Enter a number: ");
fflush(stdout);
_

今、類推により、人々はfflush(stdin)が未使用の入力を破棄すべきだと考えることがよくありますが、それについて少し考えるとあまり意味がありません。入力バッファを「フラッシュ」するとはどういう意味ですか? 「フラッシュ」された場所to?出力バッファをフラッシュすると、出力は基礎となるファイルまたはターミナルに送信され、最終的には最終的には終了しますが、input“最終的には最終的にはどこになりますか?”知る方法はありません!入力ストリームデータがファイル、パイプ、またはソケットからのものである場合の動作はどうなりますか? まったく入力ストリームではfflush()の振る舞いは明確ではありませんが、すべての場合の出力ストリームでは非常に明確です。したがって、fflush()は出力ストリームに対してのみ定義されます。

fflush(stdin)の誤った使用が当たり前になった理由は、何年も前に、いくつかのオペレーティングシステムdidが多くの人々が期待したとおりに動作するスキームを実装し、未使用の入力を破棄するためです。 Microsoft DOSは良い例です。驚くべきことに、最新バージョンのLinuxは、入力ストリームにfflush()も実装しています。

「余分な」不要な端末入力を行う正しいことは、単にそれを読み取って何もしないことです。これはfflush(stdin)を呼び出すのとほとんど同じくらい簡単で、どこでも動作し、正式に未定義の動作に依存しません。

[〜#〜] c [〜#〜]標準は次のとおりです。

streamが出力ストリームまたは最新の操作が入力されていない更新ストリームを指す場合、fflush関数はそのストリームの未書き込みデータをホスト環境に配信され、ファイルに書き込まれます。 それ以外の場合、動作は未定義です

POSIXによれば (明示的に[〜#〜] c [〜#〜]に従う):

streamが出力ストリームまたは最新の操作が入力されていない更新ストリームを指す場合、fflush()はそのストリームの未書き込みデータを引き起こすファイルに書き込まれる、...

しかし、 Linux manpage はこう言います:

出力ストリームの場合、fflush()は、ストリームの基礎となる書き込み関数を介して、指定された出力または更新ストリームのすべてのユーザースペースバッファリングデータの書き込みを強制します。 入力ストリームの場合、fflush()は、基礎となるファイルからフェッチされたが、アプリケーションによって消費されていないバッファーデータを破棄します。ストリームのオープンステータスは影響を受けません。

32
Emmet

fflush(stdin)は、未定義の動作を呼び出します。

fflush()は、出力ストリームに対してのみ定義されます。してはいけません。


Unixでは、Ctrl-ZはTSTPシグナル(SIGTSTP)を送信します。これにより、デフォルトでプロセスは実行を一時停止します。

16
chrk