为什么在执行特定的按位运算时,uint64_t的高32位变为1?整数常量的类型

问题描述 投票:3回答:1

有人可以向我解释为什么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]

https://ideone.com/xKUaTe

您会注意到我给出了一个“等效”的32位版本(案例#3和#4),它们没有显示相同的行为......

c literals signed integer-promotion uint64
1个回答
3
投票

默认情况下,没有后缀的整数文字将具有类型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时产生负值

看到

© www.soinside.com 2019 - 2024. All rights reserved.