比较unsigned char和EOF

Amo*_*rma 7 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;
}
Run Code Online (Sandbox Code Playgroud)

gcc编译器也会在编译时发出警告

abc.c:13:warning: comparison is always true due to limited range of data type
Run Code Online (Sandbox Code Playgroud)

当代码unsigned char被替换为charint按预期时,代码运行正常,即它终止.
但代码也运行unsigned int良好.因为我有我读的EOF就是定义为-1stdio.h那为什么此代码为无符号的字符失败,但运行良好的unsigned int类型.

bas*_*hrc 8

写这条线的黄金法则是

   while ((ch = fgetc(stdin)) != EOF)
Run Code Online (Sandbox Code Playgroud)

ch应该是int.你使用ch无符号的可爱技巧失败,因为它EOF是一个有符号的int数量.

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

步骤1:

ch=fgetc(fp)
Run Code Online (Sandbox Code Playgroud)

fgetc()返回-1(签名int).通过C的黄金法则ch获得最后一个八位位数1.因此价值255.ch执行后的字节模式

ch = fgetc(fp); 
Run Code Online (Sandbox Code Playgroud)

因此会

11111111
Run Code Online (Sandbox Code Playgroud)

第2步:

ch != EOF
Run Code Online (Sandbox Code Playgroud)

现在EOF是一个有 符号整数,chunsigned char...

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

00000000000000000000000011111111 = (255)10
Run Code Online (Sandbox Code Playgroud)

虽然EOF

11111111111111111111111111111111 = (-1)10
Run Code Online (Sandbox Code Playgroud)

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

while ((ch = fgetc(stdin)) != EOF)
Run Code Online (Sandbox Code Playgroud)

永远不会评价为假......

因此无限循环.

  • 黄金法则总是匹配您的括号**。在两个示例中都缺少`)`,它必须是while((ch = fgetc(stdin))!= EOF)`。 (2认同)

Lun*_*din 7

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

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

所以表达式相当于

(unsigned char)ch != (int)EOF
Run Code Online (Sandbox Code Playgroud)

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

(unsigned int)ch != (int)EOF
Run Code Online (Sandbox Code Playgroud)

然后,C中的平衡规则(也就是通常的算术转换)将隐式地将int转换为unsigned int,因为每个操作数必须具有相同的类型:

(unsigned int)ch != (unsigned int)EOF
Run Code Online (Sandbox Code Playgroud)

在你的编译器EOF可能是-1:

(unsigned int)ch != (unsigned int)-1
Run Code Online (Sandbox Code Playgroud)

假设32位CPU,它与...相同

(unsigned int)ch != 0xFFFFFFFFu
Run Code Online (Sandbox Code Playgroud)

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