首页 文章

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

提问于
浏览
24

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

为什么?

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

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

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

6 回答

  • 3

    那是two's complement编码 .

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

  • -1

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

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

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

  • 1

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

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

  • 7

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

  • 46

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

    11111110 (254 or -2)
       +00000001 (  1)
       ---------
        11111111 (255 or -1)
    
        11111111 (255 or -1) 
       +00000001 ( 1)
       ---------
       100000000 ( 0 + 256)
    
  • 26

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

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

    (size_t) (SIZE_MAX + 1)

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

    请注意,上述情况属实:

    • 适用于所有无符号类型,

    • 即使底层机器没有't represent numbers in Two'补充 . 在这种情况下,编译器必须确保标识成立 .

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

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

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

    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节) .

相关问题