为什么unsigned int 0xFFFFFFFF等于int -1?

时间:2009-12-07 21:48:28

标签: c++ c casting binary

在C或C ++中,可以说size_t(无符号整数数据类型)可以容纳的最大数量与向该数据类型强制转换-1相同。例如,请参阅Invalid Value for size_t

为什么呢?

我的意思是,(谈论32位整数)AFAIK最重要的位保持符号有符号数据类型(即位0x80000000形成负数)。那么,1是0x00000001 .. 0x7FFFFFFFF是int数据类型可以容纳的最大正数。

然后,AFAIK的-1 int的二进制表示应该是0x80000001(也许我错了)。为什么/如何将这个二进制值转换为完全不同的任何东西(0xFFFFFFFF)时将int转换为unsigned?或者..如何形成0xFFFFFFFF的二进制-1?

我毫不怀疑在C :((unsigned int)-1)== 0xFFFFFFFF或((int)0xFFFFFFFF)== -1同样真实而不是1 + 1 == 2,我只是想知道为什么

6 个答案:

答案 0 :(得分:47)

C和C ++可以在许多不同的体系结构和机器类型上运行。因此,它们可以有不同的数字表示:两个补码,而Ones的补码是最常见的。通常,您不应该依赖程序中的特定表示。

对于无符号整数类型(size_t是其中之一),C标准(我认为也是C ++标准)指定了精确的溢出规则。简而言之,如果SIZE_MAX是类型size_t的最大值,那么表达式

(size_t) (SIZE_MAX + 1)

保证为0,因此,您可以确保(size_t) -1等于SIZE_MAX。对于其他无符号类型也是如此。

请注意,以上情况属实:

  • 适用于所有未签名类型
  • 即使底层机器不代表二进制补码中的数字。在这种情况下,编译器必须确保标识成立。

此外,上述意味着您不能依赖签名类型的特定表示。

编辑:为了回答一些评论:

假设我们有一个代码片段:

int i = -1;
long j = i;

分配到j时有类型转换。假设intlong具有不同的大小(大多数[全部?] 64位系统),ij的内存位置的位模式将会发生不同,因为它们有不同的大小。编译器确保ij-1

同样,当我们这样做时:

size_t s = (size_t) -1

正在进行类型转换。 -1的类型为int。它有一个位模式,但这与此示例无关,因为当转换为size_t时由于转换而发生,编译器将根据规则转换输入(在这种情况下为size_t)。因此,即使intsize_t具有不同的大小,标准也会保证上面s中存储的值将是size_t可以采用的最大值。

如果我们这样做:

long j = LONG_MAX;
int i = j;

如果LONG_MAX大于INT_MAX,则i中的值是实现定义的(C89,第3.2.1.2节)。

答案 1 :(得分:26)

它被称为二补。要得到一个负数,反转所有的位然后加1。所以要将1转换为-1,将其反转为0xFFFFFFFE,然后加1以使其为0xFFFFFFFF。

至于为什么这样做,Wikipedia说:

  

二进制补码系统的优点是不需要加法和减法电路检查操作数的符号来确定是加或减。该属性使系统更易于实现,并且能够轻松处理更高精度的算术。

答案 2 :(得分:7)

关于为什么(unsigned)-1给出最大可能的无符号值的第一个问题,只是偶然与两个补码相关。 -1转换为无符号类型的原因给出了该类型可能的最大值,因为标准表示无符号类型“遵循算术模2 n 的定律,其中n是特定大小整数的值表示。“

现在,对于2的补码,最大可能的无符号值和-1的表示恰好相同 - 但即使硬件使用另一种表示(例如1的补码或符号/幅度),将-1转换为无符号类型仍必须为该类型生成最大可能值。

答案 3 :(得分:3)

Two's complement非常适合做减法,就像添加一样:)

    11111110 (254 or -2)
   +00000001 (  1)
   ---------
    11111111 (255 or -1)

    11111111 (255 or -1) 
   +00000001 ( 1)
   ---------
   100000000 ( 0 + 256)

答案 4 :(得分:1)

那是two's complement编码。

主要的好处是,无论使用的是unsigned还是signed int,都可以获得相同的编码。如果从0减去1,则整数只是环绕。因此,小于0的1是0xFFFFFFFF。

答案 5 :(得分:-1)

因为int的位模式 -1是十六进制无符号的FFFFFFFF。 11111111111111111111111111111111二进制无符号。 但在int中,第一位表示它是否为负数。 但是在unsigned int中,第一位只是额外的数字,因为unsigned int不能为负数。因此额外的位使得unsigned int能够存储更大的数字。 与unsigned int一样11111111111111111111111111111111(二进制)或FFFFFFFF(十六进制)是uint可以存储的最大数字。 不推荐使用无符号Int,因为如果它们变为负数,则它会溢出并转到最大数字。