为何uint16_t类型变量x*x会得到错误结果?
问题原因解析
核心原因:整数提升与有符号整数溢出
我们一步步拆解问题:
变量类型自动提升
执行x*x时,C语言的整数提升规则会生效:x是uint16_t(无符号16位整数),最大值为0xFFFF(65535)。- 你的系统中
int为32位,完全能容纳uint16_t的所有取值,因此x会被自动转换为有符号32位int参与运算。
乘法运算触发溢出
65535 * 65535的结果是4294836225,但32位有符号int的取值范围仅为-2147483648到2147483647,这个结果远超上限,触发有符号整数溢出(属于C标准中的未定义行为,但GCC默认按补码回绕处理)。
溢出后结果回绕为-131071,计算逻辑:4294836225 - 2^32 = -131071。赋值时的符号扩展
溢出后的-131071是32位有符号int值,赋值给uint64_t类型的pow时会触发符号扩展:- 因原数为负数,32位补码最高位是1,扩展到64位时高32位会全部填充为1,最终得到64位值
0xfffffffffffe0001。
- 因原数为负数,32位补码最高位是1,扩展到64位时高32位会全部填充为1,最终得到64位值
printf格式符的误导
你使用%ld格式符输出pow,%ld对应有符号长整型,会把0xfffffffffffe0001解析为有符号数,显示为-131071。若改用%lu(无符号长整型),就能输出正确的无符号值18446744073602795521。
解决方法回顾
将x强制转换为uint64_t后,运算会以64位无符号整数执行,不会触发溢出:
uint64_t pow = (uint64_t)x * x;
内容的提问来源于stack exchange,提问作者Bartłomiej Bury
相关产品推荐
相关产品推荐

