2014-02-14 43 views
3

我受的size_t一些行为,我注意到困惑大得多:为size_t为0x1 << 31比为size_t为0x1 << 30

size_t zero = 0x1 << 32; 
size_t big = 0x1 << 31; 
size_t not_as_big = 0x1 << 30; 
printf("0x1<<32: %zx\n0x1<<31: %zx\n0x1<<30: %zx\n", zero, big, not_as_big); 

结果:

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

现在,我明白了size_t只保证至少是一个16位无符号整数,但我不明白为什么0x1<<31结束了它所做的值 - 试图分配18艾字节在我的程序上做了一个数字。

我在x86_64上使用LLVM。

+4

符号扩展... – Mysticial

回答

9

移位符号整数,这样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,最小的32位有符号整数作为有符号的64位整数存储。

所有64位平台的方式来做到这一点之间的正确和便携是:

((size_t)1) << 32 
((size_t)1) << 31 
+2

另一个可爱的做法是唯一有用的通用结构:'sizeof(char)<< 31'。 –

5

0x1int类型和两个表达式评估在具有32位int,一个实现:

0x1 << 32 

0x1 << 31 

调用未定义的行为。

要解决此问题(但假设你不想让zero对象评估到0),请在KarolS答案建议

(size_t) 1 << 32 

(size_t) 1 << 31 

这是假定size_t类型比32位更宽,这是在x64上执行clang时的情况。

+7

这是一个理由不这样做,并且有原因的结果不出来的普通。这不是解释这个具体价值是如何产生的,这也许是有用的。 – delnan

+0

假设32位'unsigned','size_t zero = 1U << 32;'和C11§6.5。7 3“如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。”暗示我的结果可能是'1'。 – chux

+0

@chux对,这是错误的。我修改了我的答案。 – ouah

相关问题