为何uint32_t相减后int64_t结果异常,int却得到正确值?
无符号整数减法的类型转换陷阱
核心原因:无符号整数的运算规则
C语言中,当操作数均为无符号类型时,运算结果必然是无符号类型,后续的赋值操作只是将这个无符号结果转换为目标类型,不会回溯修改运算过程的结果。
拆解两个变量的差异
int64_t diff = a - b;的问题
a和b都是uint32_t(无符号32位整数),所以a - b会按无符号规则计算:123减260000不够减时,无符号整数会触发模2^32的溢出,最终得到的结果是2^32 - (260000 - 123) = 4294707419。这个无符号正数被赋值给int64_t时,会直接高位补0扩展为64位正数,所以diff存储的是正数4294707419,自然不会满足diff < 0的判断。int diff2 = a - b;的“巧合”正确
同样先得到无符号结果4294707419,但这个值超过了32位有符号int的最大值(2147483647)。当赋值给int类型时,多数编译器会按补码规则截断低32位,而4294707419的低32位正好对应-259877的补码,所以diff2最终得到了预期的负数结果,触发diff2 < 0的判断。注意:这种行为属于未定义行为,C标准不保证所有编译器都这么处理。
正确的写法
要得到正确的有符号差值,需要先将操作数转换为有符号64位类型再运算,避免无符号运算的溢出:
int64_t diff = (int64_t)a - b;
此时a被转换为int64_t,b会被自动提升为int64_t,运算结果就是正确的-259877,diff < 0的判断也会生效。
内容的提问来源于stack exchange,提问作者budoattack
相关产品推荐
相关产品推荐

