开发者

Checking for underflow/overflow in C++?

Is there a general way to check for an overflow or an underflow of a given data type (uint32, int etc.)?

I am doing something like this:

uint32 a,b,c;开发者_如何学运维
... //initialize a,b,c
if(b < c) {
   a -= (c - b)
}

When I print a after some iterations, it displays a large number like: 4294963846.


To check for over/underflow in arithmetic check the result compared to the original values.

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

For your specific the check would be:

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


I guess if I wanted to do that I would make a class that simulates the data type, and do it manually (which would be slow I would imagine)

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;

it can be more tricky than that, you might have to wind up using a define instead of a typedef...

I did a similar thing with pointers to check where memory was being written out side of bounds. very slow but did find where memory was being corrupted


Cert has a good reference for both signed integer overflow which is undefined behavior and unsigned wrapping which is not and they cover all the operators.

The document provides the following checking code for unsigned wrapping in subtraction using preconditions is as follows:

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;
  }
  /* ... */
}

and with post-conditions:

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

If you are gcc 5 you can use __builtin_sub_overflow:

__builtin_sub_overflow( ui_a, ui_b, &udiff ) 


Boost has a neat library called Safe Numerics. Depending on how you instantiate the safe template, the library will throw an exception when overflow or underflow has occurred. See https://www.boost.org/doc/libs/1_74_0/libs/safe_numerics/doc/html/index.html.


I'll put here another possible approach in case a bigger (x2 size) integer type is available. In that case it is possible to prevent the overflow from happening at the expense of a little more computation.

// 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';
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜