7

次のコードをコンパイルすると、無限ループに入ります。

int main()
{
    unsigned char  ch;
    FILE *fp;
    fp = fopen("abc","r");
    if(fp==NULL)
    {
        printf("Unable to Open");
        exit(1);
    }
    while((ch = fgetc(fp))!=EOF)
    printf("%c",ch);
    fclose(fp);
    printf("\n",ch);
    return 0;
}

gccコンパイラはコンパイル時にも警告を出します

abc.c:13:warning: comparison is always true due to limited range of data type

コードは、にunsigned char置き換えられたとき、charまたはint期待どおりに終了したときに正常に実行されます。
ただし、コードも正常に実行さunsigned intれます。私が読んだように、EOF定義は次のよう-1stdio.hなります。なぜこのコードはunsigned charでは失敗するのに、unsignedintでは正常に実行されるのでしょうか。

4

6 に答える 6

10

この行を書くための黄金律は

   while ((ch = fgetc(stdin)) != EOF)

chint符号付き整数の量であるため、符号なしを作成するというあなたのかわいいトリックはch失敗します。EOF

さて、深みに行きましょう......

ステップ1:

ch=fgetc(fp)

fgetc()-1(署名済み)を返しますint。Cのゴールデンルールにより、chすべてのビットの最後のオクテットを取得し1ます。したがって、値255chの実行後のバイトパターン

ch = fgetc(fp); 

したがって、

11111111

ステップ2:

ch != EOF

EOF符号付き整数chあり、unsigned char...

もう一度、Cの黄金律を参照します...小さい人は比較の前chに大きいサイズに変換されるので、そのバイトパターンは現在int

00000000000000000000000011111111 = (255)10

EOFですが

11111111111111111111111111111111 = (-1)10

それらを等しくする方法はありません.......したがって、次のwhileループを操作するステートメント

while ((ch = fgetc(stdin)) != EOF)

falseと評価されることはありません...

したがって、無限ループ。

于 2011-12-21T08:26:01.840 に答える
7

いくつかの暗黙の変換が行われています。これらは特定の警告とはあまり関係がありませんが、コンパイラがその式で実際に何をするかを示すために、これらをこの回答に含めました。

  • あなたの例のchはunsignedchar型です。
  • EOFはint型(C99 7.19.1)であることが保証されています。

したがって、式は次のようになります。

(unsigned char)ch != (int)EOF

Cの整数拡張ルールは、unsignedcharをunsignedintに暗黙的に変換します。

(unsigned int)ch != (int)EOF

次に、Cのバランシングルール(別名、通常の算術変換)は、intをunsigned intに暗黙的に変換します。これは、各オペランドが同じ型である必要があるためです。

(unsigned int)ch != (unsigned int)EOF

コンパイラでは、EOFはおそらく-1です。

(unsigned int)ch != (unsigned int)-1

これは、32ビットCPUを想定すると、

(unsigned int)ch != 0xFFFFFFFFu

キャラクターがこれほど高い値を持つことは決してないので、警告です。

于 2011-12-21T08:41:32.357 に答える
2

intを使用する必要があります

fgetc()は、ファイルの終わりを示すことができるように、特にintを返します。

EOF(-1)が範囲内にあるため、signed charで正常に実行されますが、127より大きい値のcharを読み取ると機能しなくなります。

intを使用し、EOFをチェックした後でcharにキャストします

于 2011-12-21T08:16:16.717 に答える
2

私もこの問題に遭遇しました。私の解決策はfeof()を使用することです。

unsigned int xxFunc(){
  FILE *fin;
  unsigned char c;
  fin = fopen("...", "rb");
  if(feof(fin) != 0) return EOF;
  c = fgetc(fin);
  fclose(fin);
...
}

また、EOFと比較するint変数を定義できます。例えば:

int flag = xxFunc();
while(flag != EOF) {...}

これは私のために働きます。

**重要更新***

前述の方法を使用した後、深刻な問題を発見しました。feof()は、whileループを中断するための良い方法ではありません。これがその理由です。http://www.gidnetwork.com/b-58.html

だから私はこれを行うためのより良い方法を見つけます。私はそれを行うためにint変数を使用します。ここ:

int flag;
unsigned char c;
while((flag = fgetc(fin)) != EOF) 
{ 
  //so, you are using flag to receive, but transfer the value to c later.
  c = flag;
  ... 
}

私のテストの後、これは機能します。

于 2013-03-14T23:28:21.743 に答える
1

unsignedintとsignedintを比較すると、signedintがunsignedintに変換され、それらが比較されます。したがって、unsigned int'ch'を使用してファイルを読み取る場合、EOFを読み取ると(4バイトのintマシンで)2 ^ 32 + 1が得られ、EOFと比較すると、EOFがunsignedに変換されます。これも2^です。 32 + 1、したがってプログラムは停止します!

unsigned char chを使用する場合、ファイルを読み取るときにEOFを読み取ると2 ^ 32 + 1が返され、これはunsigned charにキャストされ、値が最初の8ビット(1バイトのcharマシンの場合)に切り捨てられます。 255の出力。したがって、255と2 ^ 32 + 1を比較しているため、無限ループが発生します。

ここでの問題は、比較する前に切り捨てることです。

使用する場合

while((ch = fgetc(fp))!=(unsigned char)EOF)
    printf("%c",ch);

プログラムは正常に実行されます!

于 2011-12-21T08:40:32.107 に答える
0

この種の実装では、lint警告が生成されます

タイプ「char」とEOFの比較

 // read the data in a buffer
611     ch = getc(csv_file);
612     while (ch != EOF)

修理:

// read the data in a buffer
    while ((ch = getc(csv_file)) != EOF)
于 2017-05-26T11:48:12.540 に答える