有人可以向我解释为什么 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),它没有表现出相同的行为......

最佳答案

默认情况下,如果没有后缀的整数文字适合 int ,则它们的类型为 int

因此,无论您输入多少个零,0x00000000000000FF 都将是 int。您可以通过打印 sizeof 0x00000000000000FF 来检查
因此,0x00000000000000FF << 24 的结果是 0xFF000000,这是一个负值 1。当转换为 uint64_t 时,这将再次被符号扩展,用 1 填充前 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有很多相关和重复的问题:
  • Type of integer literals not int by default?
  • What Are Integer Literal Type? And How They Are Stored?
  • what is the reason for explicitly declaring L or UL for long values
  • ...

  • 1 从技术上讲,转换为符号位会导致未定义的行为,但在您的情况下,编译器选择将结果与您移动无符号值时的结果相同:0xFFU << 24 = 0xFF000000U 转换为有符号时会产生负值

  • Bitwise shift operation in C on uint64_t variable
  • Why does shifting 0xff left by 24 bits result in an incorrect value?
  • 关于c - 为什么在执行特定的按位运算时 uint64_t 的高 32 位变为 1?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33127326/

    10-14 12:34
    查看更多