【问题标题】:Unsigned minus unsigned difference between 32 and 64-bit无符号减去 32 位和 64 位之间的无符号差异
【发布时间】:2012-08-30 06:29:17
【问题描述】:

情况:
我有一段代码在编译为 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 的情况下编译时会出现段错误。 segfault 的原因是 (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 位的情况下发生了什么?

【问题讨论】:

  • ISO 委员会称其为“永不溢出”。
  • @HansPassant:任何人,无论他们是否是 ISO 委员会,在编写标准文档时都应该准确地使用技术术语。溢出的技术定义是计算结果的量级太大而无法以所选类型表示。 C 中的整数溢出是未定义的行为,但无符号整数不能溢出——这是一个非常重要的说明,如果没有它,有些人可能会认为无符号算术可以例如发出信号。有符号溢出确实在某些平台 (MIPS) 上引发信号(崩溃)。

标签: c gcc 32bit-64bit unsigned


【解决方案1】:

在这两种情况下,您都会得到一个非常大的数字,因为 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];

【讨论】:

  • 实际上,数组索引(有效地)提升为ptrdiff_t,它通常与数据指针的宽度相同。见 6.5.6:8, :9。
  • @ecatmur:我已经阅读了 n1256 的那部分,但它没有提到 ptrdiff_t。额外挑战:你能说出sizeof(ptrdiff_t) != sizeof(void *) 的 32 位或 64 位架构吗?
  • 好点;我假设指针减法的结果类型(6.5.6:9)暗示了这一点,但实际上并非如此。奖金挑战 - 没有。
  • 很好的答案!绝对没有考虑过指针算术环绕。
猜你喜欢
  • 1970-01-01
  • 2011-01-17
  • 1970-01-01
  • 2019-03-24
  • 2012-02-11
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2010-12-18
相关资源
最近更新 更多