【问题标题】:Integer division overflows整数除法溢出
【发布时间】:2015-05-22 10:16:16
【问题描述】:

问题

我一直在考虑整数(int 类型)溢出,我突然想到除法可能会溢出。

示例:在我当前的平台上,我有

INT_MIN == -INT_MAX - 1

因此

INT_MIN < -INT_MAX

因此

INT_MIN / -1 > -INT_MAX / -1

因此

INT_MIN / -1 > INT_MAX.

因此,除法 (INT_MIN / -1) 确实会溢出。


问题

所以,我有两个问题:

  1. 可以编写什么(跨平台)C 代码来防止除法溢出(对于(有符号)int 类型)?

  2. 哪些保证(在 C 或 C++ 标准中)可能有助于设计代码?


例如,如果标准保证我们有任何一个

INT_MIN == -INT_MAX - 1

INT_MIN == -INT_MAX,

然后出现下面的代码防止溢出。

#include <limits.h>

/*
      Try to divide integer op1 by op2.
      Return
        0 (success) or
        1 (possibly overflow prevented).
      In case of success, write the quotient to res.
*/

int safe_int_div(int * res, int op1, int op2) {

  /*   assert(res != NULL);   */
  /*   assert(op2 != 0);      */

  if ( op1 == INT_MIN && op2 == -1 )  {
    return 1;
  }
  *res = op1 / op2;
  return 0;
}

【问题讨论】:

  • OT:按照惯例,您希望在出错时返回 -1
  • @Anon。如果您还添加诸如if (!op2) return 2 之类的内容,则可以解决另一个除法问题:)
  • 这与计算机如何在硬件上进行除法有关

标签: c++ c cross-platform standards integer-overflow


【解决方案1】:

哪些保证(在 C 或 C++ 标准中)可能有助于设计代码?

C 指定有符号整数表示为使用 3 种形式中的一种:符号和幅度、二进制补码或二进制补码。鉴于这些形式,只有被 0 和 INT_MIN/-1 的补码除法可能会溢出。

可以编写什么(跨平台)C 代码来防止除法溢出(对于(有符号的)int 类型)?

int safe_int_div(int * res, int op1, int op2) {
  if (op2 == 0) {
    return 1;
  }
  // 2's complement detection
  #if (INT_MIN != -INT_MAX) 
    if (op1 == INT_MIN && op2 == -1)  {
      return 1;
    }
  #endif
  *res = op1 / op2;
  return 0;
}

【讨论】:

  • 值得一提的是,如果您在没有上述保护措施的情况下尝试分割​​INT_MIN/-1,HW(CPU 架构、FPGA 或某些 RTL)可能会停止。
  • 或者下划线内核/固件没有正确处理异常。
【解决方案2】:

1) 就像 C 中的任何其他操作一样,应用程序必须确保:

  • 用于计算本身的类型足够大,并且
  • 存储结果的变量类型足够大。

确保这一点的方法是在操作之前设置每个操作数的大小限制。适合的限制取决于算法和变量的用途。

2) 如果您使用 C 标准的 stdint.h,您可以保证变量有多大,可移植。编写可移植代码时,切勿使用int

对于编写安全除法例程的情况,它将32位整数作为参数,然后对64位整数进行计算,并将结果作为32位整数返回。

#include <stdint.h>
#include <stdbool.h>

/*
      Try to divide integer op1 by op2.
      Return
        true (success) or
        false (possibly overflow prevented).
      In case of success, write the quotient to res.
      In case of failure, res remains untouched.
*/

bool safe_int_div (int32_t* res, int32_t op1, int32_t op2) {

  if(op2 == 0)
    return false;

  int64_t res64 = (int64_t)op1 / (int64_t)op2;

  if(res64 > INT32_MAX || res64 < INT32_MIN)
    return false;

  *res = (int32_t)res64_t;

  return true;
}

如果需要有关除法失败原因的更多信息,请将布尔值替换为枚举。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-30
    • 2022-01-21
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 2020-10-22
    相关资源
    最近更新 更多