web-dev-qa-db-ja.com

C stdioの 'ungetc'関数が存在するのはなぜですか?

Cプログラミング言語(およびCの標準と直接インターフェイスするか、Cの標準の複製を作成した後続の多くの言語IO functions))には、 ngetc という関数が存在します。 int ungetc(int char, FILE *stream);。読み込まれているストリームの先頭にcharを「返します」。このプットバックは仮想のみであり、元の入力ストリームは変更されず、後続の「getc」呼び出しの結果のみが変更されますストリームの実際の次の値に進む前に、最初に「ungetc」の値を読み取ります。

なぜこの機能が存在するのですか? 「ungetc」を使用することによってのみ処理できる使用例の例は何ですか?

6
Qqwy

簡単に言えば、ungetc 次の文字を消費せずに覗くことができます

パケット化されたデータ形式を読んでいるとしましょう。特に、フレーム同期パターンが含まれます。フレーム同期パターンを使用すると、同期されていないデータストリームのデータフレームの先頭にマークを付けることで、データを整列できます。

議論を容易にするために、ここにデータ定義があります:

[sync pattern] [packet length] [--------------data--------------] [checksum]

|---0xEB25---| |-- 16 bits --| |-- packet length minus 64 bits--| |32 bits |

同期パターンEB25を選択する理由はいくつかあります。そのビットパターンは誤検知に耐性があり、ファイルタイプ「マジックナンバー」として機能するのに十分ユニークです。

チェックサムは、送信エラーを検出し、同期パターンを検証するためにあります(EB25には実際に有効なデータである可能性が少ないため)。正確なパケット長と組み合わせると、同期パターン、パケット長、およびチェックサムの組み合わせにより、有効なデータパケットが識別されたことが実質的に保証されます。

ここで、データストリームの前のポイントにバックアップする機能がない状態で、この演習を行うことを想像してください。次のパケットを見つけるには、EB25の同期パターンが見つかるまでバイトをスキャンする必要があります。これは、仕様がリトルエンディアンに基づいているため、バイトが逆になっていることを考慮しています。同期パターンを特定したら、パケット長を読み取ってから、残りのパケットを読み取り、チェックサムを計算する必要があります。チェックサムチェックが失敗した場合は、失敗した同期パターンの次のバイトから最初からやり直す必要があります。これを行うには、同期パターンの先頭+ 4バイトにバックアップする必要があります。 、再度スキャンを開始します。

これまでのところ、入力ストリームをバッファリングしても達成できないことについては説明していません。しかし、同期パターンがの場合はどうでしょうか。バイト境界での整列が保証されていませんか?その状況では、同期パターンの最初のビットがバイトの中央で発生する可能性があります。したがって、最初の8ビットを取得するには、1バイトではなく2バイトを読み取る必要があります。これらの状況下で、連続する8ビットがEでない場合(バッファーされたリーダーを立ち上げることなく)、1バイト逆方向にスクラブすると便利ではないでしょうか?

これは単なるアイドルの仮説ではありません。 IRIG 106 Chapter 10仕様はこの方法で正確に機能しますが、このデモンストレーションのために話を少し簡略化しました。

16
Robert Harvey