无符号减去32和64位之间的无符号差

时间:2012-09-05 13:54:50

标签: c gcc 32bit-64bit unsigned

情况:
我有一段代码在编译为32位时有效,但在使用gcc 4.6编译为64位时失败。在确定问题并阅读标准之后,我无法理解为什么它适用于32位。我希望有人可以解释发生了什么。

代码(稍微简化并缩减为有趣的部分):

// tbl: unsigned short *, can be indexed with positive and negative values
// v: unsigned int
// p: unsigned char *
tmp = tbl[(v >> 8) - p[0]]; // Gives segfault when not compiled with -m32

使用-m32编译时,代码可以正常工作。在没有-m32的情况下进行编译时,它会产生段错误。段错误的原因是(v >> 8) - p[0]在编译为64位时被解释为unsigned int,对于“否定”结果将被解除。

根据this问题,C99标准说明如下:
6.2.5c9:A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

由此看来,unsigned减去unsigned总是会产生unsigned输出,这与64位情况下的情况一致。这似乎不会发生在32位的情况下,这是我觉得非常奇怪的。

任何人都可以解释32位情况下发生了什么吗?

1 个答案:

答案 0 :(得分:14)

在这两种情况下,你得到一个非常大的数字,因为unsigned int包裹,但在32位的情况下,指针算术包裹,所以它取消了。

为了进行指针运算,编译器将数组索引提升到与指针相同的宽度。因此对于具有32位指针的unsigned,您可以获得与具有32位指针的int相同的结果。

例如,

char *p = (char *) 0x1000;

// always points to 0x0c00
// in 32-bit, the index is 0xfffffc00
// in 64-bit, the index is 0xfffffffffffffc00
int r = p[(int) -0x400]; 

// depends on architecture
// in 32-bit, the index is 0xfffffc00 (same as int)
// in 64-bit, the index is 0x00000000fffffc00 (different from int)
int r = p[(unsigned) -0x400];