[ZZ]ところでgetch ar()などの関数の戻り値
2990 ワード
住所:http://www.wscxy.com/shosh/article.asp?id=13
【文章の原作者:Antigloss】
多くの初心者はchar型変数でgetar、getc、fgetcなどの関数の戻り値を受け取ることに慣れていますが、実はこれは間違いです.
致命的なエラー.getch arなどの関数の戻り値の種類は全部です.
int型は、これらの関数が
読み込みエラーまたは
書類を読んだら、戻ってきます.
EOFEOFはマクロであり、標準ではその値は必ず一つであることを規定しています.
int型のマイナス定数です.通常コンパイラはEOFを
-1です.問題はここにあります.char型変数を使ってgetarなどの関数の戻り値を受信するとEOFの認識エラーや、間違ったデータをEOFと間違えたり、EOFを良いデータと間違えたりします.たとえば:
int c; /* 正しいです.int型変数を使ってfgetcの戻り値を受信するべきです.*/ while((c=fgetc(fp))!=EOF) { puttar(c) }
上記の例に示すように、fgetcなどの関数の戻り値を一つの変数で受信してから、この変数とEOFを使って比較して、ファイルが読み終わったかどうかを判断する場合が多いです.上記の例は正しいです.fgetcから返されたEOFを正確に受信できるようにcを定義して、この比較の正確性を保証します.char型だと思わぬ結果になります.
まず、fgetcなどの関数の戻り値がint型であるため、char型変数に値が与えられた場合には、ダウングレードが発生し、データが遮断されます.
(c=fgetc(fp))!=EOF /* cの値は常に正の値ですが、標準ではEOFは負の値*/
つまり次のサイクルは死のサイクルです.
while((c=fgetc(fp))!=EOF) { puttar(c) }
ここまで読むと、「cをシンプルなタイプと定義しておけば大丈夫ですよね」という読者の友達がいるかもしれません.残念ながら、cをsigned charと定義しても、誤りです.fgetcなどの関数が1バイトの値をFFと読んだら、戻り値は00 FFです.この値をcに割り当てたら、cの値はFFになります.そして、cの値はEOFと比較するために自動的にint型の値にアップグレードされます.つまり、FF FF FF FF FFです.以下の式は成立しません.
(c=fgetc(fp))!=EOF /* FFの文字を読んで、EOF*/と間違えました.
つまり、以下のループはファイルを読み終えていない場合は早めに終了します.
while((c=fgetc(fp))!=EOF) { puttar(c) }
以上のように、char型変数を使ってfgetcなどの関数の戻り値を受信するのは間違いです.int型変数を使ってこれらの関数の戻り値を受信し、受信した値がEOFかどうかを判断しなければなりません.戻り値がEOFではないと判断した場合にのみ、char型変数に値を付与することができます.
同じように、C++では、char型変数でcin.get()の戻り値を受信するのも間違いです.しかし、char型変数をパラメータとしてcin.getに渡すのは正しいです.
char c=cin.get() //誤り、理由は同じです. char c; cin.get(c) //正しいです
【文章の原作者:Antigloss】
多くの初心者はchar型変数でgetar、getc、fgetcなどの関数の戻り値を受け取ることに慣れていますが、実はこれは間違いです.
致命的なエラー.getch arなどの関数の戻り値の種類は全部です.
int型は、これらの関数が
読み込みエラーまたは
書類を読んだら、戻ってきます.
EOFEOFはマクロであり、標準ではその値は必ず一つであることを規定しています.
int型のマイナス定数です.通常コンパイラはEOFを
-1です.問題はここにあります.char型変数を使ってgetarなどの関数の戻り値を受信するとEOFの認識エラーや、間違ったデータをEOFと間違えたり、EOFを良いデータと間違えたりします.たとえば:
int c; /* 正しいです.int型変数を使ってfgetcの戻り値を受信するべきです.*/ while((c=fgetc(fp))!=EOF) { puttar(c) }
上記の例に示すように、fgetcなどの関数の戻り値を一つの変数で受信してから、この変数とEOFを使って比較して、ファイルが読み終わったかどうかを判断する場合が多いです.上記の例は正しいです.fgetcから返されたEOFを正確に受信できるようにcを定義して、この比較の正確性を保証します.char型だと思わぬ結果になります.
まず、fgetcなどの関数の戻り値がint型であるため、char型変数に値が与えられた場合には、ダウングレードが発生し、データが遮断されます.
---------------------------------
| | int | char |
|--------|--------------|-------|
| 10 | 00 00 00 0A | 0A |
| -1 | FF FF FF FF | FF |
| -2 | FF FF FF FE | FE |
---------------------------------
ここでは、intとcharはそれぞれ32ビットと8ビットと仮定します.上の表からはint型からchar型まで3バイトのデータが失われました.char型とint型を比較すると、char型は自動的にint型にアップグレードされます.char型がint型にアップグレードされた後の値は、それがsigned charなのかunsigned charなのか、不幸なのかを区別します.はい、もし私たちがsignedやunsignedを使ってcharを修飾しなかったら、charがunsigned charを指すのかそれともsigned charを指すのかは分かりません.コンパイラによって決められています.でも、charがsignedであろうと、unsignedであろうと、char型変数を使ってfgetcなどの関数の値を受け取ることは変えられません.このエラーに戻ります.実際に、唯一変更できるのはこのエラーによる結果です.前に述べたように、char型とint型の比較では、charは自動的にintにアップグレードされます.次に、signed charとunsigned charがintに変換した後、それらの値はどのような違いがありますか?---------------------------------------
| char | unsigned | signed |
|-------|---------------|-------------|
| 10 | 00 00 00 0A | 00 00 00 0A |
| FF | 00 00 00 FF | FF FF FF FF |
| FE | 00 00 00 FE | FF FF FF FE |
---------------------------------------
上の表からわかるように、charがunsignedの場合、intに変換された値は正の値です.つまり、cをchar型変数と定義してコンパイラがデフォルトのcharをunsigned charとすると、以下の表式は永遠に成立します.(c=fgetc(fp))!=EOF /* cの値は常に正の値ですが、標準ではEOFは負の値*/
つまり次のサイクルは死のサイクルです.
while((c=fgetc(fp))!=EOF) { puttar(c) }
ここまで読むと、「cをシンプルなタイプと定義しておけば大丈夫ですよね」という読者の友達がいるかもしれません.残念ながら、cをsigned charと定義しても、誤りです.fgetcなどの関数が1バイトの値をFFと読んだら、戻り値は00 FFです.この値をcに割り当てたら、cの値はFFになります.そして、cの値はEOFと比較するために自動的にint型の値にアップグレードされます.つまり、FF FF FF FF FFです.以下の式は成立しません.
(c=fgetc(fp))!=EOF /* FFの文字を読んで、EOF*/と間違えました.
つまり、以下のループはファイルを読み終えていない場合は早めに終了します.
while((c=fgetc(fp))!=EOF) { puttar(c) }
以上のように、char型変数を使ってfgetcなどの関数の戻り値を受信するのは間違いです.int型変数を使ってこれらの関数の戻り値を受信し、受信した値がEOFかどうかを判断しなければなりません.戻り値がEOFではないと判断した場合にのみ、char型変数に値を付与することができます.
同じように、C++では、char型変数でcin.get()の戻り値を受信するのも間違いです.しかし、char型変数をパラメータとしてcin.getに渡すのは正しいです.
char c=cin.get() //誤り、理由は同じです. char c; cin.get(c) //正しいです