为什么“ unsigned int”与EOF没有区别-它可以存储负值吗?

时间:2019-03-26 04:15:45

标签: c

我试图逐位读取位图文件,并且有一个循环运行,直到到达EOF。为此,我有一个声明为unsigned int的变量,用于存储每个字节。当此变量等于EOF时,循环停止。

有趣的一点是:如果我将变量声明为unsigned int,它将起作用。但是,如果我将变量声明为unsigned short int,则循环将永远运行,因为它永远找不到EOF

#include <stdio.h>

int main()
{
    FILE *file;
    unsigned int currentByte;

    file = fopen("/home/stanley/Desktop/x.bmp", "rb");

    while ((currentByte = fgetc(file)) != EOF) {
        printf("%d \n", currentByte);
    }

    fclose(file);
    return 0;
}

上面的代码是我正在编写的代码。如果文件大小为90B,则会在屏幕上打印90个字节。

但是,由于某种原因,当我将其更改为unsigned short int currentByte时,循环将永远运行。好像currentByte从未等于EOF

我在某处读到EOF包含负值(-1)。但是,如果EOF为负数,为什么当我仅使用unsigned int时它起作用,为什么当我使用unsigned short int时它会出错?从理论上讲,问题不应该与unsigned本身有关,而不是与short有关吗?无法签名的人不能存储负值。

很抱歉,这是一个非常愚蠢的问题。我试图更好地理解位和字节的工作方式,有些概念对我来说可能还很陌生。

我正在以下环境中对其进行编译:

  • 操作系统:Ubuntu 18.04 x64
  • 海湾合作委员会:海湾合作委员会(Ubuntu 7.3.0-27ubuntu1〜18.04)7.3.0

先谢谢了。 :)

3 个答案:

答案 0 :(得分:3)

如果int的大小大于short的大小,那么您将遇到此问题。

我们假设EOF的类型为int,并包含值-1。为了举例说明,我们还假设int是32位值,而short是16位值。

在这种情况下,如果fgetc返回EOF,当作为unsigned int时它将具有0xFFFFFFFF的值。将其与EOF(类型int)进行比较时,有符号整数-1将转换为无符号值0xFFFFFFFF。这两个值相等,因此比较可以按预期进行。

但是,由EOF返回的fgetc被视为unsigned short,其值为0xFFFF。因为unsigned short的大小小于int的大小,所以当将此值与EOF进行比较时,unsigned short 0xFFFF将转换为值为0x0000FFFF的int (为清楚起见,显示了额外的数字)。由于对于32位值,-1不等于0xFFFF,因此此比较始终不相等,并且循环不会停止。

fgetc返回int的事实提示您应将其保留为该类型,否则将丢弃某些信息或导致比较混乱。

答案 1 :(得分:2)

您应该使用类型int来匹配fgetc返回的内容,而不是unsigned int。循环停止条件与unsigned int一起工作的原因不是值永远为负,而是当!=运算符与对象的unsignedsigned操作数一起使用时排名相同,都在比较之前被提升为unsigned。将EOF的{​​{1}}结果分配给fgetc并将currentByte提升为EOF都会产生相同的结果,因此它们比较相等。

答案 2 :(得分:2)

当您将有符号整数转换为无符号整数时(将EOF分配给无符号整数变量时会发生这种情况),通过加UINT_MAX + 1将结果转换为无符号整数。因此,如果EOF-1,则该值将变为UINT_MAX

并且UINT_MAX仅适合unsigned int而不适合unsigned short。 并且这种特殊转换的结果是实现定义的,因此程序的行为将取决于它。

请注意,fgetc函数将返回int,因此必须使用int变量来存储其值。