[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型変数に値が与えられた場合には、ダウングレードが発生し、データが遮断されます.
---------------------------------

|      |      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)         //正しいです