有符号/无符号整数运算取值范围对abs输出结果的影响疑问
现象底层原理解答
核心前置知识
- C语言默认做整数运算前会执行整数提升:所有宽度小于
int的整型(包括int8_t/uint8_t/int16_t在32位/64位系统下都满足),都会先转换为int再参与运算 - 有符号整型用补码存储,小宽度有符号整型转大宽度有符号整型时会做符号扩展,保持数值不变而非保持二进制位不变
abs函数的参数是int类型,返回值也是int类型
场景1:temp1、temp2为int8_t类型
int8_t是8位有符号整型,取值范围-128 ~ 127:
0x3a对应十进制值58,在范围内,值保持为580xfb二进制最高位为1,作为补码对应十进制值251 - 256 = -5
运算过程:temp1 - temp2 = 58 - (-5) = 63,abs(63) = 63,十六进制为0x3f,和输出一致。
场景2:temp1、temp2为int16_t类型
int16_t是16位有符号整型,取值范围-32768 ~ 32767:
0x3a对应值580xfb十进制为251,在正范围内,值保持为251
运算过程:temp1 - temp2 = 58 - 251 = -193,abs(-193) = 193,十六进制为0xc1,和输出一致。
场景3:temp1、temp2为uint8_t类型
uint8_t是8位无符号整型,取值范围0 ~ 255:
0x3a对应值580xfb对应值251
运算过程:
两个值先提升为int再运算,58 - 251 = -193,abs(-193) = 193 = 0xc1,和输出一致。
强制转换场景的结果解释
你将int8_t类型的变量强制转换为int16_t时,遵循有符号类型转换规则:
- 原
int8_t类型的temp1值为58,转int16_t后仍为58 - 原
int8_t类型的temp2值为-5,转int16_t时做符号扩展,值仍为-5,而非你预期的251(只有无符号转换/截断才会保持二进制位不变)
运算过程还是58 - (-5) = 63,abs(63) = 0x3f,和实际输出一致。
如果要得到0xc1的结果,你需要将int8_t的变量先强制转换为uint8_t再转int16_t,保证二进制位按无符号解析:
printf("%x", abs((int16_t)(uint8_t)temp1 - (int16_t)(uint8_t)temp2));
内容的提问来源于stack exchange,提问作者Waad
相关产品推荐
相关产品推荐

