检查C ++中的下溢/溢出?

时间:2010-03-08 04:21:18

标签: c++ overflow integer-overflow underflow

是否有通用的方法来检查给定数据类型(uint32,int等)的溢出或下溢?

我正在做这样的事情:

uint32 a,b,c;
... //initialize a,b,c
if(b < c) {
   a -= (c - b)
}

当我在经过一些迭代后打印时,会显示一个很大的数字,如:4294963846。

5 个答案:

答案 0 :(得分:9)

要检查算术中的上溢/下溢,请检查结果与原始值的比较。

uint32 a,b;
//assign values
uint32 result = a + b;
if (result < a) {
    //Overflow
}

具体来说,检查将是:

if (a > (c-b)) {
    //Underflow
}

答案 1 :(得分:4)

我想如果我想这样做,我会创建一个模拟数据类型的类,并手动完成(这将是我想象的慢)

class MyInt
{
     int val;
     MyInt(const int&nval){ val = nval;} // cast from int
     operator int(){return val;} // cast to int

    // then just overload ALL the operators... putting your check in
};

//typedef int sint32;
typedef MyInt sint32;

它可能比那更棘手,你可能不得不最后使用define而不是typedef ......

我做了类似的事情,用指针检查内存写在边界的哪一边。非常缓慢,但确实找到了内存被破坏的地方

答案 2 :(得分:3)

Cert对signed integer overflow(未定义的行为)和unsigned wrapping都有很好的参考,但不包括所有运营商。

该文件使用前置条件为减法中的无符号包装提供以下检查代码如下:

void func(unsigned int ui_a, unsigned int ui_b) {
  unsigned int udiff;
  if (ui_a < ui_b){
    /* Handle error */
  } else {
    udiff = ui_a - ui_b;
  }
  /* ... */
}

以及后置条件:

void func(unsigned int ui_a, unsigned int ui_b) {
  unsigned int udiff = ui_a - ui_b;
  if (udiff > ui_a) {
    /* Handle error */
  }
  /* ... */
}

如果您gcc 5,则可以使用__builtin_sub_overflow

__builtin_sub_overflow( ui_a, ui_b, &udiff ) 

答案 3 :(得分:0)

Boost 有一个简洁的库,称为 Safe Numerics。根据您实例化安全模板的方式,库将在发生溢出或下溢时抛出异常。见https://www.boost.org/doc/libs/1_74_0/libs/safe_numerics/doc/html/index.html

答案 4 :(得分:0)

我将在这里提出另一种可能的方法,以防更大(x2 大小)整数类型可用。在这种情况下,可以通过增加一点计算来防止溢出的发生。

// https://gcc.godbolt.org/z/fh9G6Eeah
#include <exception>
#include <limits>
#include <iostream>

using integer_t = uint32_t; // The desired type
using bigger_t = uint64_t; // Bigger type

constexpr integer_t add(const integer_t a, const integer_t b)
   {
    static_assert(sizeof(bigger_t)>=2*sizeof(integer_t));
    constexpr bigger_t SUP = std::numeric_limits<integer_t>::max();
    constexpr bigger_t INF = std::numeric_limits<integer_t>::min();
    // Using larger type for operation
    bigger_t res = static_cast<bigger_t>(a) + static_cast<bigger_t>(b);
    // Check overflows
    if(res>SUP) throw std::overflow_error("res too big");
    else if(res<INF) throw std::overflow_error("res too small");
    // Back to the original type
    return static_cast<integer_t>(res); // No danger of narrowing here
   }


//---------------------------------------------------------------------------
int main()
{
    std::cout << add(100,1) << '\n';
    std::cout << add(std::numeric_limits<integer_t>::max(),1) << '\n';
}