c语言 - size_t 0x1<<31 比 size_t 0x1<<30 大得多

  • 本文关键字:size 0x1 语言 c size-t
  • 更新时间 :
  • 英文 :


我对我注意到的size_t的一些行为感到困惑:

size_t zero = 0x1 << 32;
size_t big = 0x1 << 31;
size_t not_as_big = 0x1 << 30;
printf("0x1<<32: %zxn0x1<<31: %zxn0x1<<30: %zxn", zero, big, not_as_big);

结果:

0x1<<32: 0
0x1<<31: ffffffff80000000
0x1<<30: 40000000

现在,我知道size_t只能保证至少是一个16位无符号整数,但我不明白为什么0x1<<31最终会得到它的值——试图分配18 EB在我的程序中造成了一个数字。

我在x86_64上使用LLVM。

移动一个有符号整数,使1进入符号位位置,或者在C中进一步移动是未定义的,因此编译器可以自由执行以下操作:

0x1 << 32

在这里,编译器看到一个32位int(0x1),它被移位了32位。由于编译器可以自由地以与更正确的移位一致的方式对其进行解释,因此它将其解释为0x1_0000_0000,并尝试将其转换为32位int,从而生成0x0000_0000,然后看到您稍后将结果分配给size_t,通常为64位:0x0000_0000_0000_0000

0x1 << 31

和以前一样,编译器可以自由地对它做任何看起来正确的事情,因为1位侵入了符号位的位置。所以结果是0x8000_0000,这是一个负数——准确地说是INT_MIN。然后,它看到你将负数转换为64位,所以它用1来扩展它,就像所有负数一样。结果是0xffff_ffff_8000_0000,它是作为有符号64位整数存储的最小32位有符号整数。

在所有64位平台之间正确且可移植的方法是:

((size_t)1) << 32
((size_t)1) << 31

0x1的类型为int,在使用32位int的实现中,两个表达式都求值:

0x1 << 32

0x1 << 31

调用未定义的行为。

要解决此问题(但假设您不想让zero对象求值为0),请按照KarolS答案中的建议进行操作

(size_t) 1 << 32

(size_t) 1 << 31

这假设size_t类型比32位宽,x64上的clang实现就是这样。

相关内容

  • 没有找到相关文章

最新更新