如何检查数字是否溢出'int'

时间:2012-12-01 16:50:19

标签: c integer-overflow

  

可能重复:
  Best way to detect integer overflow in C/C++

我在接受采访时被问到这个问题:“将数字的字符串表示转换为整数”。但是如果数字超过可以存储在32位整数中的最大值,则必须抛出错误。 我的问题是我们如何检查一个数字是否溢出32位无符号整数?

3 个答案:

答案 0 :(得分:9)

在循环中,您已获得由第一个数字确定的整数的当前值。你将要这样做:

curval = curval * 10 + digit;  // digit converted from '0'..'9' to 0..9 already

您可以使用以下方法测试溢出:

if (curval > UINT32_MAX / 10 || (curval == UINT32_MAX / 10 && digit > UINT32_MAX % 10))
    ...overflow would occur...
else
    curval = curval * 10 + digit; // overflow did not occur

除法和模数运算是编译时操作,而不是运行时操作。

这种方法比使用“大于32位的无符号整数进行计算”的一个优点是,它可以扩展为使用更大的整数 - 使用64位整数和uintmax_t整数 - 通过更改从UINT32_MAX到UINT64_MAX或UINTMAX_MAX的常量。这就是必要的(当然,除了改变变量类型之外)。


同样的基本测试也适用于签名类型,但是增加了复杂性。使用16位整数更容易进行演示(输入和思考的数字更少),所以我将切换到16位二进制补码short

  • USHRT_MAX = 65535
  • SHRT_MAX = 32767
  • SHRT_MIN = -32768

问题是short类型可以存储-32768但是你可以累积的最大正值是32767.对于除SHRT_MIN之外的所有值,上面的测试都可以正常工作。有办法绕过这种困境。一种是在计算过程中将curval存储为负值,并在返回前将其否定,如果它应为正数。然后你的测试可能是:

if (curval < SHRT_MIN / 10 || (curval == SHRT_MIN / 10 && digit > -(SHRT_MIN / 10))
    ...overflow would occur...
else
    curval = curval * 10 - digit; // Note subtraction!

在否定负值之前,您仍需检查curval是否为SHRT_MIN。 (理论上,你应该检查-SHRT_MAX != SHRT_MIN以允许除了二进制补码二进制之外的其他系统;我为限制引用的值满足该条件。)

当然,同样的想法和技巧适用于INT_MAXINT32_MAXINT64_MAXINTMAX_MAX

答案 1 :(得分:6)

(我查看了这个问题的possible duplicate,我不确定阅读的有用性,因为在面试环境中,你可以期待描述一般的想法/方法)


回答面试问题的一部分是提出澄清问题(面试官期待您的重要检查表项目之一)。

因此,您的调查线至少应包含以下内容:

  • 您是否可以使用unsigned long long / uint64_t(64位整数)?
  • 字符串来自哪里? stdin /从文件中读取/硬编码为字符串文字?
  • 它是作为十进制表示给你的吗?二进制/八进制/十六进制?
  • 应该抛出什么样的错误?我们是否尝试恢复并继续执行?什么是故障安全默认值?

假设您的面试官告诉您它是十进制表示+您可以使用unsigned long long

  • 首先检查位数:32位unsigned int范围介于0 to 4,294,967,295之间。如果数字的十进制字符串表示形式超过10个字符(超过10个数字),则它已经溢出;提出错误。
  • 接下来,将号码保存到unsigned long long并除以UINT32_MAX+1=4294967296。如果结果大于0,则溢出;提出错误。

答案 2 :(得分:0)

使用uint64_t进行转换。你将一次添加一个数字;对于每个数字,您将乘以10并添加下一个字符的值。处理完每个字符后,检查结果是否大于UINT32_MAX;如果是,则退出并出现错误(或者溢出时应该做的任何事情)。完成后,将号码作为uint32_t返回。 uint64_t中定义了uint32_tUINT32_MAXstdint.h