有人可以向我解释为什么uint64_t
的高32位在#2的情况下被设置为1:
uint64_t ret = 0;
ret = (((uint64_t)0x00000000000000FF) << 24);
printf("#1 [%016llX]\n", ret);
ret = (0x00000000000000FF << 24);
printf("#2 [%016llX]\n", ret);
uint32_t ret2 = 0;
ret2 = (((uint32_t)0x000000FF) << 8);
printf("#3 [%08X]\n", ret2);
ret2 = (0x000000FF << 8);
printf("#4 [%08X]\n", ret2);
#1 [00000000FF000000]
#2 [FFFFFFFFFF000000]
#3 [0000FF00]
#4 [0000FF00]
您会注意到我给出了一个“等效”的32位版本(案例#3和#4),它们没有显示相同的行为......
默认情况下,没有后缀的整数文字将具有类型int
,如果它们适合int
。
The type of the integer constant
整数常量的类型是值可以适合的第一种类型,从类型列表中取决于使用哪个数字基数和
integer-suffix
。
- 没有后缀 小数基数: INT 长整数 unsigned long int(直到C99) long long int(自C99起) 二进制,八进制或十六进制基数: INT unsigned int 长整数 unsigned long int long long int(自C99起) unsigned long long int(自C99起)
- ...
因此0x00000000000000FF
是一个int
,无论你输入多少零。你可以通过打印sizeof 0x00000000000000FF
检查
因此,0x00000000000000FF << 24
导致0xFF000000,这是负值1。当再次投射到uint64_t
时,这将再次符号扩展,用前缀填充前32位
正如你在(uint64_t)0x00000000000000FF) << 24
所看到的那样,施放帮助,因为现在这个转变是以uint64_t
值而非int
运行的。您也可以使用后缀
0x00000000000000FFU << 24
0x00000000000000FFULL << 24
上面的第一行是unsigned int
的转变,然后做零延伸以投射到uint64_t
。第二个直接在unsigned long long
进行操作
0x000000FF << 8
没有暴露相同的行为,因为结果是0xFF00没有设置符号位,但如果你做(int16_t)0x000000FF << 8
它会
有很多相关和重复的问题:
1从技术上切换到符号位会导致未定义的行为,但在您的情况下,编译器选择保留与移位无符号值时相同的结果:0xFFU << 24 = 0xFF000000U当转换为signed时产生负值
看到