3

有人可以向我解释一下为什么在 #2 的情况下 a 的高 32 位uint64_t设置为 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),它没有表现出相同的行为......

4

1 回答 1

3

默认情况下,不带后缀的整数文字int如果适合int.

整数常量的类型

整数常量的类型是值可以适合的第一种类型,来自类型列表,这取决于使用的数字基数和integer-suffix使用的类型。

  • 无后缀
  • 十进制基数:
    • 整数
    • 长整数
    • 无符号长整数(C99 前)
    • long long int (C99 起)
  • 二进制、八进制或十六进制基数:
    • 整数
    • 无符号整数
    • 长整数
    • 无符号长整数
    • long long int (C99 起)
    • unsigned long long int (C99 起)
  • ...

因此,无论您输入多少个零,结果0x00000000000000FF都将是一个。您可以通过打印来检查intsizeof 0x00000000000000FF

因此,0x00000000000000FF << 24结果 0xFF000000 是负值1。投射到 时,这将再次被符号扩展uint64_t,用 1 填充前 32 位

如您在 中所见,投射帮助,(uint64_t)0x00000000000000FF) << 24因为现在 shift 作用于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转换为有符号时会产生负值

于 2018-09-28T04:02:22.757 回答