VOID. FIO35-C. sizeof(int) == sizeof(char) の場合、ファイル終端およびファイルエラーの検出には feof() と ferror() を使用する
このガイドラインは廃止され、以下のガイドラインに統合されました。
char
型が16ビットかそれ以上であり int
型が char
型と同じサイズであるような処理系では、fgetc()
、getc()
、getchar()
などの文字入出力関数の返す値が EOF
であるかどうかの区別がつかないことがある。C 言語規格は、このような処理系において EOF
文字が通常の文字と区別できることを保証していない。そのため、このような処理系でストリームの終端やエラーフラグを確認するには、feof()
や ferror()
関数を使用する必要がある[Kettlewell 2002]。
この問題は大きな文字セットを使用するワードマシンで発生しうる。
UTF-16 では 0xFFFF
が文字を表さないことが保証されており、EOF
の値として −1 を使うことができる。16 ビット EUC (Exteded UNIX Code) では、どの文字についても上位バイトは 0xFF
にはならないため、衝突が発生する余地はまったくない。同様に、すべての UTF-32 文字は符号付き32ビット整数としてみた場合正の値をとる。このように、今後新たな文字セットをデザインするときには、C言語におけるこの種の問題が起きないように注意する必要がある。
このガイドラインはワイド文字の扱いにも適用される。sizeof(wint_t) == sizeof(wchar_t)
が成立するプラットフォームでは、ファイル終端を検出する目的でワイド文字を WEOF
と比較してはいけない。Ubuntu Linux や Mac OS X が稼働する64ビットシステムでは、wint_t
も wchar_t
も32ビット幅の型である。
違反コード
以下のコード例では、ループ終了条件として文字データ c
が EOF
と等しいかどうかをテストしている。
#include <stdio.h> void func(void) { int c; do { c = getchar(); } while (c != EOF); }
EOF
は負の値であり、他の任意の unsigned char
と異なる値であることが保証されているが、int
に変換された場合に他と異なる値であることは保証されない。int
と char
が同じサイズの場合、上記コードのループは思ったより早く終了してしまう可能性がある。
適合コード (可搬性のある方法)
以下の適合コードでは、feof()
を使ってファイル終端に達しているかどうか、また、ferror()
を使ってエラーが発生しているかどうかをテストしている。
#include <stdio.h> void func(void) { int c; do { c = getchar(); } while (!feof(stdin) && !ferror(stdin)); }
適合コード (明らかに可搬性のない方法)
この適合コードではアサートを使うことで、このコードが動作することが保証されるアーキテクチャでのみ実行されるようにしている。PRECISION()
マクロの定義については「INT35-C. 整数型の精度を正しく求める」を参照。
#include <assert.h> #include <stdio.h> void func(void) { int c; assert(PRECISION(UCHAR_MAX) < PRECISION(INT_MAX)); do { c = getchar(); } while (c != EOF); }
例外
FIO35-EX1: C 標準関数には、文字を返さないが EOF
を返り値として返すものがある。このような関数には、fclose()
、fflush()
、fputs()
、fscanf()
、puts()
、scanf()
、sscanf()
、vfscanf()
、vscanf()
がある。これらの関数の返り値は正しく EOF
と比較することができる。
FIO35-EX2: そのプログラムが動作するすべてのプラットフォームで int
が表現できる範囲が char
よりも広いことが保証されるならば、文字を EOF
と比較してもよい。これらの型のサイズが同じである処理系はまれであり、ほとんどの場合この条件があてはまる。
リスク評価
C 標準は、int
型が +32767 を表現でき、char
型が int
型よりも大きくないことのみを要求している。したがって、一般的ではないが、整数定数式 EOF
が通常の文字と区別できないような状況、つまり (int)(unsigned char)65535 == -1
となる場合が考えられる。それゆえ、sizeof(int) == sizeof(char)
であるようなまれな処理系では、feof()
や ferror()
を使って EOF
やエラーを検知しないと EOF
文字を正しく識別できなくなる恐れがある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
FIO35-C |
低 |
低 |
中 |
P2 |
L3 |
自動検出
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
5.0 |
|
CERT C Rule Pack を使ってこのルールの違反を検出できる |
関連するガイドライン
CERT C コーディングスタンダード | FIO34-C. ファイルから読み込んだ文字と EOF や WEOF を区別する DCL03-C. 定数式の値をテストするには静的アサートを使う |
SEI CERT C++ Coding Standard | VOID FIO35-CPP. Use feof() and ferror() to detect end-of-file and file errors when sizeof(int) == sizeof(char) |
参考資料
[Kettlewell 2002] | Section 1.2, "<stdio.h > and Character Types" |
[Summit 2005] | Question 12.2 |
翻訳元
これは以下のページを翻訳したものです。
void FIO35-C. Use feof() and ferror() to detect end-of-file and file errors when sizeof(int) == sizeof(char) (revision 86)