比较unsigned char和EOF

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

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 。 因为我已经读过EOFstdio.h定义为-1然后为什么这个代码对unsigned char失败但是对unsigned int运行正常。

写这条线的黄金法则是

  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是有符号整数chunsigned char

我再次提到C的黄金法则……在比较之前,较小的家伙ch被转换为大尺寸int ,所以它的字节模式现在是

 00000000000000000000000011111111 = (255)10 

虽然EOF

 11111111111111111111111111111111 = (-1)10 

它们无法平等…….因此,引导以下while循环的语句

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

永远不会评价为假……

因此无限循环。

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

  • 你的例子中的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 

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

我也遇到过这个问题。 我的解决方案是使用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; ... } 

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

你需要使用一个int

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

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

使用int,在检查EOF后将其强制转换为char

将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); 

你的程序运行正常!

通过这种实现产生了一个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)