对有符号和无符号整数执行操作时的范围



我注意到了一些奇怪的事情,如果有人能帮助我更深入地了解正在发生的事情,我将不胜感激。

temp1 = 0x3a
temp2 = 0xfb
printf("%x", abs(temp1 - temp2))

如果 temp1、temp2 的类型为int8_t,将打印0x3f

如果 temp1、temp2 的类型为int16_t,将打印0xc1

如果 temp1、temp2 的类型为uint8_t,将打印0xc1

现在我明白int16_8和uint8_t有更大的正范围,但我仍然不明白发生了什么,我尝试了int8_t并使用铸造

printf("%x", abs((int16_t) (temp1) - (int16_t)(temp2)))

程序打印0x3f(我预计会得到0xc1),这真的很令人困惑

如果temp1temp2的类型为int8_t,则temp1 = 0x3atemp1设置为58(0x3a的值),但它是由实现定义的temp2 = 0xfb设置temp2,因为0xfb(251)的值对于int8_t来说太大了。通常,C 实现会将其设置为 −5(等于 251−256,并且在二进制补码中具有与 251 在无符号二进制中相同的位编码)。

那么temp1 - temp2是 58 − −5 = 63,其中绝对值为 63,即0x3f的值。

如果temp1temp2的类型为int16_tuint8_t,则temp1 = 0x3a像以前一样将temp1设置为 58,temp2 = 0xfb设置为temp2设置为 251。

temp1 - temp2是 58 − 251 = −193,其中绝对值为 193,即0xc1的值。注意,在temp1 - temp2的求值中,类型int16_tuint8_t的值会自动提升为int,因此算术是使用int类型完成的,即使temp1temp2的类型uint8_t,也会产生-193。