12

情况:
我有一段代码在编译为 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]被解释为unsigned int当编译为 64 位时,“负”结果将是很远的。

根据这个问题,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 位的情况下发生了什么?

4

1 回答 1

14

在这两种情况下,你都会得到一个非常大的数字,因为unsigned int环绕,但在 32 位的情况下,指针算法也会环绕,所以它抵消了。

为了进行指针运算,编译器将数组索引提升为与指针相同的宽度。因此,对于unsigned32 位指针,您会得到与int32 位指针相同的结果。

例如,

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];
于 2012-09-05T14:00:06.390 回答