EOF(ファイルの終わり)文字をchar型に格納する


11

EOF値を保持できるようにEOF値を十分に大きくするために、EOFを保持する変数に使用する必要があるデニスリッチーのThe C Programming Language本を読みました。ただし、次のコードは正常に機能します。intchar

#include<stdio.h> 

main()  { 
  char c; 
  c=getchar(); 
  while(c!=EOF)  { 
    putchar(c); 
    c=getchar(); 
  } 
} 

入力がなくなると、getcharEOFを返します。また、上記のプログラムではc、char型の変数が正常に保持できます。

なぜこれが機能するのですか?上記の本の説明によると、コードは機能しません。



5
このコードは、値を持つ文字を読み取ると失敗する可能性があります0xff。の結果を保存するとgetchar()intその問題が解決します。あなたの質問は、comp.lang.c FAQの質問12.1と本質的に同じで、優れたリソースです。(また、するmain()必要がありint main(void)return 0;終了前にaを追加しても問題ありません}。)
キーストンプソン

1
@delnan:リンクされた記事は、Unixがcontrol-Dをどのように扱うかについて正しくありません。入力ストリームを閉じません。コンソール上でブロックしているfread()を未読のままのデータですぐに返すだけです。多くのプログラムは、fread()からのゼロバイトの戻り値をEOFを示すものと解釈しますが、実際にはファイルは開いたままで、より多くの入力を提供できます。
supercat

回答:


11

暗黙的な型変換が偶然に正しく行われるため、コードは機能しているようです。

getchar()は、intの範囲に収まる値unsigned charまたはである値を返しますEOF(負である必要があり、通常は-1です)。それEOF自体はキャラクターではなく、利用可能なキャラクターがもうないというシグナルであることに注意してください。

以下からの結果保管する場合getchar()ではc、2つの可能性があります。どちらのタイプcharも値を表すことができますc。その場合、それはの値です。または、型は値を表すchar ことができません。その場合、何が起こるかは定義されていません。Intelプロセッサは、新しいタイプに適合しない上位ビットを切り捨てます(256を法とする値を効果的に減らしcharます)が、それに頼るべきではありません。

次のステップはと比較cすることEOFです。以下のようEOFであるintcに変換されるintに格納された値を保存するだけでなくccの値を保存できた場合EOF、比較は成功しますが、値を保存cできなかった場合、EOFtypeへの変換中に回復不可能な情報の損失があったため、比較は失敗しcharます。

あなたのコンパイラが作成することを選んだようだchar符号付きの型との値EOFに収まる小さな十分char。場合はchar符号なした(またはあなたが使用した場合unsigned char)ので、あなたのテストは、失敗していたunsigned charの値を保持することはできませんEOF


また、コードに2番目の問題があることに注意してください。以下のようEOFな文字そのものではなく、あなたにそれを強制charタイプ、ものと誤解されますそこに文字が非常に可能性がありEOF、それらが正しく処理される場合、それは定義されていない半分の可能な文字については。


型に強制変換char範囲外の値をCHAR_MIN.. CHAR_MAX、実装定義の値を得たトラップ表現としてのビットパターン実装定義をもたらす、または実装定義信号を上げるのいずれかに必要とされるであろう。ほとんどの場合、2の補数の削減以外のことを行うには、実装に多くの追加作業が必要になります。標準化委員会の人々が、コンパイラーが他のほとんどのコンパイラーの動作と整合性のある動作を実装するよう奨励されるべきであるという考えに同意しない場合、そうしない理由はありません
...-supercat

...私はそのような強制を信頼できるものと見なします(コードがその意図を文書化するべきではないと言うのではなく、それ(signed char)xはより明確でちょうど安全であると考えられるべき((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)です)。今日の標準に準拠する他の動作を実装するコンパイラ。1つの危険性は、「最適化」という想定された目的で動作を壊すために規格が変更される可能性があることです。
-supercat

@supercat:この規格は、コンパイラがターゲットとするプロセッサで自然にサポートされていない動作を持つコードを生成する必要がないように書かれています。未定義の動作の大部分は、すべてのプロセッサが一貫して動作するわけではないため(標準を書いている時点では)存在しています。コンパイラーが成熟するにつれて、コンパイラー作成者は未定義の動作を利用して、より積極的な最適化を開始しました。
バートヴァンインゲンシェナウ

歴史的には、標準の意図は主にあなたが説明したとおりでしたが、標準では、いくつかの一般的なプラットフォームのコンパイラがより緩い仕様で必要とされるよりも多くのコードを生成することを要求するように、いくつかの動作を十分詳細に説明しています。型強制int i=129; signed char c=i;はそのような動作の1つです。-127から+127の範囲にあるときにc等しくiなりi、2の補数の縮小とは異なる-128から+127の範囲の値への他の値の一貫したマッピングを生成する命令を持つプロセッサは比較的少数です。 ..
スーパーキャット

...そのような場合、常に信号を発します。標準では、実装が一貫したマッピングを生成するか、信号を一貫して発生させる必要があるため、標準が2の補数の削減以外の余地を残す唯一のプラットフォームは、飽和演算ハードウェアを備えたDSPのようなものです。未定義の振る舞いの歴史的根拠については、問題はハードウェアプラットフォームだけのものではないということです。でもオーバーフローが非常に一貫した方法で振る舞うのプラットフォーム上で、...コンパイラのトラップそれを持っていることが有用であり得る
supercat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.