【问题标题】:Detecting overflow for integer in C检测C中整数的溢出
【发布时间】:2018-08-26 11:54:47
【问题描述】:
#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 扫描一个整数并输入一个超出整数范围的整数,会发生什么?值在存储时会发生变化吗?

【问题讨论】:

  • 您需要设计一个示例并尝试一下。这是一个您可以通过反复试验自行回答的问题。
  • "这个程序反转一个有符号整数。"这是什么意思?
  • @nicomp:反复试验只揭示了一个 C 实现的功能(或尽可能多的实现),而不是 C 标准所说的。
  • @Stargateur:从代码中可以清楚地看出,他们正在反转数字的十进制数字中的有效数字。
  • @EricPostpischil 我“应该”不需要阅读代码来理解;)但是反转一个数字在数学上没有多大意义,所以我要求澄清这些信息。跨度>

标签: c integer-overflow


【解决方案1】:

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

  1. 如何检测整数运算中的溢出?
  2. 如何在 scanf 等转换函数中检测 ovetflow?

答案如下。

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

【讨论】:

  • 感谢您的回答。我正在尝试检查溢出,检查 y 的值是否大于 INT_MAX/10。
【解决方案2】:

在标准 C 中,溢出是一种异常情况,因此每个标准都未定义行为。来自 C11 的 n1570 草案,6.5 表达式 § 5:

如果在计算表达式期间出现异常情况(即,如果 结果未在数学上定义或不在其可表示值的范围内 type),行为未定义。

这意味着您不能按照标准定义的方式处理溢出。话虽如此,大多数编译器只是保留结果的低位以适合类型表示并忽略最高位。这就是 MSVC、gcc 和 clang 所做的。

从现在开始,我将假设您的系统使用 int32_t(分别为 int16_tint64_t)作为有符号整数并忽略溢出。它不是每个标准都强制执行的,但很常见,并且可能是您的系统所做的。

您的代码中有 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...
    ...

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

【讨论】:

  • 感谢您的回答。是的,我正在尝试丢弃输入并检查逆向操作中的溢出。
猜你喜欢
  • 1970-01-01
  • 2019-08-23
  • 2012-01-21
  • 2012-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多