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)



