【问题标题】:Check for int overflow in C++在 C++ 中检查 int 溢出
【发布时间】:2015-10-17 09:51:07
【问题描述】:

我正在运行一个在 for 循环中添加数字的 C++ 程序:

int y = 0;
for (int i=0; i<NUM; i++) {
  int pow = 1;
  for (int j=0 j<i; j++) {
    pow *= 10;
  }
  y+= vec[i]*pow; // where vec is a vector of digits
}

但我不确定如何检查是否发生溢出。有什么办法吗?

【问题讨论】:

标签: c++ integer integer-overflow


【解决方案1】:

正如彼得正确地explained标准 C++11(或C99)中的溢出是undefined behavior,你真的应该是afraid of UB

但是,一些编译器为您提供了处理和检测整数溢出的扩展。

如果您可以限制自己使用最近的 GCC 编译器,则可以使用它的 integer overflow builtins

您还可以将自己限制在 int32_t 并在 int64_t 中计算算术,并检查高于 INT32_MAX 或低于 INT32_MIN 的结果。这可能比使用编译器特定的扩展更慢(但更便携)。顺便说一句,一些编译器也有一些 __int128_t 类型(因此您可以在 __int128_t 中计算算术并同样检查结果是否适合 int64_t)。

如果您的目标是拥有 arbitrary precision arithmetic,最好使用一些现有的 bignum 库,例如 GMPlib(因为 高效 bignum 算法需要非常聪明的算法)。

【讨论】:

    【解决方案2】:

    有符号整数变量的溢出会导致未定义的行为。结果是,一旦发生溢出,就不能在标准 C++ 中可靠地检测到。任何行为都是允许的。因此,您的实现(编译器、库、工具集等)可能会提供一种检测整数溢出的特定方法 - 但这种方法不一定适用于其他实现。

    唯一的方法是在执行操作(或一系列操作)之前检查潜在的溢出。或者设计您的方法(例如选择限制)以防止发生溢出。

    【讨论】:

      【解决方案3】:

      有不同的选择,可能没有一种适合所有情况和需要。

      例如,在这种情况下,您可以在相乘之前检查pow 是否小于或等于INT_MAX/10。这是有效的,因为INT_MAX/10 是最大的数字,因此它乘以 10 最多为INT_MAX。请注意,如果您将 INT_MAX/10 插入代码中,编译器通常会预先计算它(否则,如果它打扰您,您可以将其放入局部变量中):

      int y = 0;
      for (int i=0; i<NUM; i++) {
        int pow = 1;
        for (int j=0 j<i; j++) {
          if( pow > INT_MAX/10 )
             throw OverflowException;
          pow *= 10;
        }
        y+= vec[i]*pow; // where vec is a vector of digits
      }
      

      此解决方案的缺点是,如果其他因素不是恒定的,则编译器(和您)无法合理地避免在运行时进行除法 INT_MAX/n(除法通常比乘法更昂贵)。

      另一种可能性是您可以在更广泛的类型中进行计算。例如:

      int y = 0;
      for (int i=0; i<NUM; i++) {
        int32_t pow = 1;
        for (int j=0 j<i; j++) {
          int64_t tmp = (int64_t)pow * (int64_t)10;
      
          if( tmp > (int64_t)INT32_MAX )
               raise OverflowException;
      
          pow = (int32_t)tmp;
        }
        y+= vec[i]*pow; // where vec is a vector of digits
      }
      

      这有一个缺点,首先可能无法使用更宽的类型,如果是,则可能需要软件实现乘法(例如 32 位系统上的 64 位),这意味着乘法速度较慢。

      另一种情况是两个整数相加。如果发生溢出,结果将小于这两个整数,特别是如果它们都是正数,则结果将为负数。

      【讨论】:

        猜你喜欢
        • 2011-01-24
        • 1970-01-01
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-09
        • 2012-11-19
        • 1970-01-01
        相关资源
        最近更新 更多