为什么结果是unsigned int(1)的"2" - unsigned int(0xFFFFFFFF)

lin*_*xer 4 c

请查看以下代码:

#include <stdlib.h>
#include <stdio.h>


int main()
{
    unsigned int a = 1;
    unsigned int b = -1;

    printf("0x%X\n", (a-b));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果是0x2.

我认为整数提升不应该发生,因为"a"和"b"的类型都是unsigned int.但结果打败了我......我不知道原因.

顺便说一下,我知道算术结果应该是2,因为1 - ( - 1)= 2.但是b的类型是unsigned int.将(-1)赋值给b时,b的值实际上是0xFFFFFFFF.它是unsigned int的最大值.当一个小的无符号值减去一个大值时,结果不是我所期望的.

从下面的答案中,我认为溢出可能是一个很好的解释.现在我写了其他测试代码.它证明了溢出的答案是正确的.

#include <stdlib.h>
#include <stdio.h>

int main()
{
    unsigned int c = 1;
    unsigned int d = -1;


    printf("0x%llx\n", (unsigned long long)c-(unsigned long long)d);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果是"0xffffffff00000002".这是我期待的.

Kei*_*son 8

unsigned int a = 1;
Run Code Online (Sandbox Code Playgroud)

这将初始化a为1.实际上,由于1是型的int,有一个隐含的int-到- unsigned转换,但它是一个简单的转换不改变的值或表示).

unsigned int b = -1;
Run Code Online (Sandbox Code Playgroud)

这更有趣. -1是类型int,初始化隐式将其转换intunsigned int.由于数学值-1不能表示为a unsigned int,因此转换非常重要.这种情况下的规则是(引用C标准第6.3.1.3节):

通过重复加或减一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内.

当然,只要结果相同,它实际上不必这样做.添加UINT_MAX+1(" 比新类型中可表示的最大值多一个 ")为-1 UINT_MAX.(该添加是以数学方式定义的;它本身不受任何类型转换的影响.)

实际上,分配-1给任何无符号类型的对象是获取该类型的最大值而不必引用其中*_MAX定义的宏的好方法<limits.h>.

因此,假设一个典型的32位系统,我们有a == 1b == 0xFFFFFFFF.

printf("0x%X\n", (a-b));
Run Code Online (Sandbox Code Playgroud)

减法的数学结果是-0xFFFFFFFE,但这显然超出了范围unsigned int.无符号算术的规则类似于无符号转换的规则; 结果是2.

  • @linuxer:我不确定我理解这个问题.严格来说,无符号类型不会溢出或下溢,但这只是对单词含义的狡辩.您可以将"1 - 0xFFFFFFFF"视为下溢,产生一个超出"unsigned int"范围的数学结果,然后将其调整回范围,产生2.数学上,结果以"UINT_MAX + 1"模数减少. (4认同)