比较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 char
被char
或int
替换时,代码运行正常,即它终止。
但代码也适用于unsigned int
。 因为我已经读过EOF
在stdio.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
是有符号整数 , ch
是unsigned 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)