C 中的无符号整数下溢

Unsigned integer underflow in C

我在网站上看到多个关于无符号整数的问题 overflow/underflow。 大多数关于underflow的问题都是问关于将一个负数赋给一个无符号整数;我不清楚的是当 unsigned int 从另一个 unsigned int 中减去时会发生什么,例如a - b 结果是否定的。标准的相关部分是:

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.

在这种情况下,您如何解释 "reduced"?是不是说UINT_MAX+1到负数结果>= 0

我看到 this question 解决了要点(基本上说标准选择谈论 溢出 但要点是 modulo 也适用于下溢)但我仍然不清楚:

假设a-b的结果是-1;根据标准,操作 -1%(UINT_MAX+1) 将 return -1 (解释为 here);所以我们回到了起点。

这可能过于迂腐,但是这个 modulo 是指数学模而不是 C 的计算模吗?

您发布的标准部分讨论的是溢出,而不是下溢。

"Does it mean that UINT_MAX+1 is added to the negative result until it is >= 0?"

你可以这么想。抽象的结果是一样的。已经有人问过类似的问题。检查此 link:Question about C behaviour for unsigned integer underflow 了解更多详细信息。

另一种思考方式是,例如,-1 原则上来自类型 int(即 4 个字节,其中所有位均为 1)。然后,当您告诉程序将所有这些位 1 解释为 unsigned int 时,它的值将被解释为 UINT_MAX.

首先,低于给定整数类型的最小值的结果在 C 中不称为 "underflow"。术语 "underflow" 是为浮点类型保留的,意味着完全不同的东西.超出整数类型的范围总是溢出,无论您越过范围的哪一端。因此,在这种情况下,您没有看到语言规范谈论 "underflow" 确实没有任何意义。

其次,你对"reduced"这个词的意思完全正确。通过从 "mathematical" 结果中添加(或减去)UINT_MAX+1 直到它 returns 进入 unsigned int 的范围来定义最终值。这也和欧几里德"modulo"运算是一回事。

在引擎盖下,加法或减法是按位和符号独立的。生成的代码可以使用相同的指令,而不管它是否被签名。解释结果的是其他运算符,例如 a > 0。按位加或减,这会告诉您答案。 b0 - b1 = b111111111 答案与符号无关。只有其他运算符将有符号类型的答案视为 -1,无符号类型的答案为 0xFF。该标准描述了这种行为,但我总是发现最容易记住它是如何工作的,并推断出我正在编写的代码的后果。

signed int adds(signed int a, signed int b)
{
    return a + b;
}

unsigned int addu(unsigned a, unsigned b)
{
    return a + b;
}


int main() {
    return 0;
}

->

adds(int, int):
  lea eax, [rdi+rsi]
  ret
addu(unsigned int, unsigned int):
  lea eax, [rdi+rsi]
  ret
main:
  xor eax, eax
  ret