求助:GCC中位运算结果不符合预期,求分析原因
求助:GCC中位运算结果不符合预期,求分析原因
各位大佬好,我为了调试自己的学习项目写了这段代码,但运行结果和预期不符,想请大家帮忙找找问题:
我的代码如下:
#include <stdint.h> #include <stdio.h> int main(){ uint64_t number = 0; for (uint8_t i = 0; i<4; i++){ number |= 0xFF<<(8*i); printf("%032lb %lu\n",number,number); } return 0; }
运行后得到的输出(第三行内容未完整显示):
00000000000000000000000011111111 255 00000000000000001111111111111111 65535 00000000111111111111111111111111
我本来预期每次循环都能给number的对应8位填上1,但到第三次循环时结果就不对了,有没有大佬能分析下原因?
问题分析与解决方案
嘿,这个问题我遇过!核心原因是整数常量0xFF的类型是有符号int,而不是你以为的无符号64位类型,导致左移操作触发了未定义行为:
- 在C语言里,像
0xFF这种十六进制常量默认是signed int类型(通常是32位); - 当
i=0和i=1时,左移0位、8位,结果都在32位有符号int的范围内,转成uint64_t后也正常,所以输出符合预期; - 当
i=2时,左移16位,0xFF<<16的结果是0xFF0000,依然在32位int范围内,结果还是正常的; - 但当
i=3时,左移24位,0xFF<<24会把32位有符号int的最高位(符号位)置为1,这就触发了C语言的未定义行为——有符号整数左移导致符号位改变是标准未定义的,GCC处理这种情况的结果自然和你预期的不一样。
解决方法超简单,只需要把0xFF强制转换成uint64_t,让左移操作在无符号64位的上下文里执行:
number |= (uint64_t)0xFF << (8 * i);
这样每次左移都是针对64位无符号数进行的,不会有符号位的问题,最终输出就会是你预期的:每次循环给对应8位填满1,最终得到全32位1的0xFFFFFFFF。
备注:内容来源于stack exchange,提问作者Евгений Шпиц
相关产品推荐
相关产品推荐

