情况:
我有一段代码在编译为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位情况下发生了什么吗?
答案 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];