检测C中整数的溢出

时间:2018-08-26 11:54:47

标签: c integer-overflow

#include <stdio.h>

int reverse(int);
int reverse(int x) {
  int negative = 0;
  if (x < 0)
    negative = x;
  if (negative != 0) {
    x = 0 - x;
  }
  int y = 0, temp;
  while (x > 0) {
    temp = x % 10;
    x = x / 10;
    y = (y * 10) + temp;
  }
  if (negative == 0) {
    return y;
  } else {
    return 0 - y;
  }
}
int main() {
  int x, y;
  printf("Enter your number: \n");
  scanf("%d", &x);
  y = reverse(x);
  printf("The reversed number is: %d\n", y);
  return 0;
}

此程序将反转带符号的整数。我无法检查受尊敬的整数y是否超出范围。我无法在溢出主题上弄清楚。如果我要求编译器使用scanf扫描整数并输入超出整数范围的整数,会发生什么?存储时值会改变吗?

2 个答案:

答案 0 :(得分:1)

您似乎对溢出有两个不同的问题。

  1. 如何用整数算术检测溢出?
  2. 如何在诸如scanf之类的转换函数中检测ovetflow?

答案如下。

  1. 没有通用的方法,您必须根据具体情况进行操作。例如,如果y <= INT_MAX / 10,则可以确保y * 10不会溢出。 ... + temp也是如此。
  2. scanf和朋友没有其他方法来保护您免受溢出的影响,除了限制字段宽度并因此限制输入范围(但是,如果您正在读取小数,则不能将范围完全限制为INT_MAX )。如果扫描的值不适合目标类型,则行为未定义。安全转换确切范围的字符串的唯一方法是与strtol和朋友。这些函数检测溢出并相应地设置errno

答案 1 :(得分:0)

在标准C中,溢出是一个例外情况,然后按标准未定义行为。摘自n1570 for C11,6.5表达式§5:

  

如果在表达式的求值过程中发生异常情况(即   结果没有在数学上定义,或者不在其可表示的值范围内   类型),行为是不确定的。

这意味着您不能按照标准定义溢出方式。话虽这么说,大多数编译器只是保留结果的低阶位以适合类型表示,而忽略最高阶位。这就是MSVC,gcc和clang的作用。

从现在开始,我将假设您的系统使用int32_t(分别为int16_tint64_t)来签名int并忽略溢出。它不是每个标准都强制要求的,但足够通用,很可能是您的系统所要做的。

您的代码中可能有2个溢出。首先是scanf函数:如@ n.m。所说,如果输入序列不适合该类型,则对于该函数系列的行为不作任何说明。我将假定提交的数字可以作为带符号的int接受(介于INT_MIN和INT_MAX之间)。无论如何,让用户检测到它是微不足道的:仅显示x:如果它不是唯一键入的数字,则发生溢出。

第二个在这里:

y = (y * 10) + temp;

在这里,通过执行反向操作并控制一切都很好,很容易测试溢出:

int next = (y * 10) + temp;
if ((next < 0) || (y != (next - temp) / 10)) {
    // an overflow occured...
    ...

从理论上讲,没有什么可以保证否定一个正整数是一个有效的负整数,但这对于intXX_t类型是正确的,因此足以检测到reverse函数中的溢出