【问题标题】:Question about C behaviour for unsigned integer underflow关于无符号整数下溢的 C 行为问题
【发布时间】:2011-02-15 04:09:28
【问题描述】:

我在很多地方读到无符号整数溢出在 C 中的定义与有符号对应项不同。

下溢也一样吗?

例如:

unsigned int x = -1; // Does x == UINT_MAX?

谢谢。

我不记得在哪里,但我在某处读到无符号整数类型的算术是模块化的,所以如果是这种情况,那么 -1 == UINT_MAX mod (UINT_MAX+1)。

【问题讨论】:

  • 我相信术语“下溢”只真正适用于浮点数,在浮点数中你不能表示一些非常接近零的数字。整数不会有这个问题。
  • @bde 我同意这是一个技术上准确的陈述,但由于违反了数字系统底端的边界条件,该术语经常被超载。

标签: c integer types integer-overflow underflow


【解决方案1】:

§6.2.5,第 9 段:

涉及无符号的计算 操作数永远不会溢出,因为 无法表示的结果 得到的无符号整数类型是 减少模数是一 大于最大值 可以用结果来表示 输入。

编辑:

对不起,错误的参考,但结果仍然是固定的。正确的参考是§6.3.1.3(有符号和无符号整数转换):

如果新类型是 无符号,值转换为 反复加减一 超过最大值可以 以新类型表示,直到 该值在新的范围内 输入。

是的,x == UINT_MAX

【讨论】:

  • 您的参考很好,但不适用,因为表达式 -1 涉及有符号操作数,而不是无符号操作数。
  • 问题已经承认溢出是明确定义的。问题是关于负数,而不是正数。
  • @Doug, @Mark:问题是关于从有符号整数到无符号整数的转换,由 §6.3.1.3 指定。
  • +1 表示正确答案,§6.3.1.3 似乎是一种非常扭曲的方式,要求 (unsigned int)(-1) == UINT_MAX 不一定要求有符号数字使用二进制补码。
  • @Stephen,感谢您的坚持(以及挖掘 6.3.1.3);我站得更正了。被接受的答案太糟糕了stackoverflow.com/questions/50605/…“数字的内部表示没有改变”
【解决方案2】:

-1,当表示为 2 的补数时,等于 0xFF...F,表示您的数字有多少位。在无符号数空间中,该值是可能的最大值(即所有位都已设置)。因此是的,x == UINT_MAX。以下代码在 C99 严格编译器上发出“1”:

#include <stdio.h>
#include <stdint.h>
#include <limits.h>

int main(int argc, char **argv){
  uint32_t x = -1;      
  printf("%d", x == UINT_MAX ? 1 : 0);
  return 0;
}

【讨论】:

  • 标准是否要求补码数?
  • 不,标准不要求2s补码,所以这个方案不通用;看我的回答。
  • uint32_t的最大值不要求为UINT_MAX-UINT_MAX,可以小到65535,大到ULONG_MAX。如果您将 uint32_t 更改为 unsigned 将是正确的。
  • 在 n 位无符号存储空间中存储负数 X 需要存储与 X mod 2ⁿ 一致的最小非负数。由于任何二进制补码有符号数 Y 的位模式将编码无符号值 Y 或 Y+2ⁿ,两者都是全等 mod 2ⁿ,其中一个将是最小的非负数,即全等 mod 2ⁿ,这意味着二进制补码遵循无符号整数的行为 - 反之亦然。
【解决方案3】:

您正在混合有符号和无符号数字,这很不酷。

unsigned int x = 0u - 1u; // is OK though

【讨论】:

  • 它可能不酷也可能不酷,但它是完美定义的符合标准的 C。
  • @Stephen Canon,不真实。 -1 的按位表示未定义。例如,它可以是补码。
  • @Stepen,“标准符合”也许,但“定义明确”?这就是问题的症结所在。
  • -1(或任何有符号整数)的按位表示不包括在内。 §6.3.1.3 指定行为。
  • 谢谢,斯蒂芬,你是对的。不过,Lint 更喜欢我的解决方案。 ;-)
猜你喜欢
  • 2023-03-15
  • 1970-01-01
  • 2011-09-03
  • 1970-01-01
  • 2013-04-10
  • 2014-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多