检查C ++中的int溢出

时间:2015-10-17 09:51:08

标签: c++ integer integer-overflow

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

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
}

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

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

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

例如,在这种情况下,您可以在乘法之前检查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 } (并且除法通常比乘法更昂贵)。

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

  # reviewer
  has_one :reviewer
  accepts_nested_attributes_for :reviewer
  has_many :active_managements, class_name: 'Reviewer',
                                foreign_key: 'reviewer_id',
                                dependent: :destroy
  has_one :my_reviewer, through: :reviewer, source: :user

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

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

答案 2 :(得分:0)

正如彼得正确的explained标准 C ++ 11(或C99)中的溢出是undefined behavior ,你真的应该{ {3}}

但是,有些编译器会为您提供扩展来处理和检测整数溢出。

如果您可以将自己限制在最近的afraid of UB编译器中,则可以使用其GCC

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

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