比较unsigned char和EOF

时间:2011-12-21 08:11:33

标签: c comparison eof unsigned-char fgetc

当编译以下代码时,它进入无限循环:

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 charcharint替换为预期时,代码运行正常,即终止。
但代码也适用于unsigned int。 正如我在EOF中读到的那样在-1中定义为stdio.h然后为什么这个代码对unsigned char失败,但对unsigned int运行正常。

6 个答案:

答案 0 :(得分:8)

写这一行的黄金法则是

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

ch应为int 。让ch无符号失败的可爱技巧失败,因为EOF是一个有符号的int数量。

好的,我们现在进入深度......

第1步:

ch=fgetc(fp)

fgetc()返回-1(签名int)。通过C ch的黄金规则获得所有1的最后一个八位字节。因此值255。执行

ch的字节模式
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)

永远不会评估为假...

因此无限循环。

答案 1 :(得分:7)

有几个隐式转换正在进行中。它们与特定警告并不真正相关,但我将它们包含在这个答案中,以显示编译器对该表达式的真正作用。

    你的例子中的
  • ch是unsigned char类型。
  • EOF保证为int类型(C99 7.19.1)。

所以表达式等同于

(unsigned char)ch != (int)EOF

C中的整数提升规则将隐式地将unsigned char转换为unsigned int:

(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

角色永远不会有这么高的值,因此警告。

答案 2 :(得分:2)

你需要使用int

fgetc()返回一个特定的int,以便它可以指示文件的结尾

它使用signed char运行正常,因为EOF(-1)在范围内,但是如果你读入一个值大于127的char,它会破坏。

使用int,在检查EOF

后将其强制转换为char

答案 3 :(得分:2)

我也遇到过这个问题。我的解决方案是使用feof()。

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

您可以定义一个int变量来与EOF进行比较。例如:

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;
  ... 
}

经过我的测试,这是有效的。

答案 4 :(得分:0)

将unsigned int与signed int进行比较时,会将signed int转换为unsigned int并进行比较。因此,当您使用unsigned int'ch'读取文件时,读取EOF会给出2 ^ 32 + 1(在4字节int机器上),并且在将其与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);

你的程序运行正常!

答案 5 :(得分:0)

使用这种实现产生lint警告

  

比较'char'类型与EOF

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

FIX:

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