Checking for Underflow/Overflow in C++

Checking for underflow/overflow in C++?

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
}

How can I correctly check that integer underflow and overflow will not happen before subtraction?

template<class I>
bool valid_add( I lhs, I rhs ) {
static constexpr I max = std::numeric_limits<I>::max();
static constexpr I min = std::numeric_limits<I>::min();

if( rhs > 0 && lhs > max - rhs ) return false;
if( rhs < 0 && lhs < min - rhs ) return false;

return true;
}
template<class I>
bool valid_subtract( I lhs, I rhs ) {
static constexpr I max = std::numeric_limits<I>::max();
static constexpr I min = std::numeric_limits<I>::min();

if ((rhs < 0) && (lhs > max + rhs)) return false;
if ((rhs > 0) && (lhs < min + rhs)) return false;

return true;
}

note that the two functions are basically asking the same question. First we ask "what direction will rhs move our result from lhs". Then we check if lhs is "far enough away" from the min or max in that direction.

In your code simply inject:

if (!valid_add(val, rhs))
throw "whatever";

and

if (!valid_subtract(val, rhs))
throw "whatever";

you'll need to change this code if not using it on integral types. On floating point types, there are more complications.

After you check that the operation is valid, simply do it. Don't call another function.

How to detect integer overflow in C

You can predict signed int overflow but attempting to detect it after the summation is too late. You have to test for possible overflow before you do a signed addition.

It's not possible to avoid undefined behaviour by testing for it after the summation. If the addition overflows then there is already undefined behaviour.

If it were me, I'd do something like this:

#include <limits.h>

int safe_add(int a, int b)
{
if (a >= 0) {
if (b > (INT_MAX - a)) {
/* handle overflow */
}
} else {
if (b < (INT_MIN - a)) {
/* handle underflow */
}
}
return a + b;
}

Refer this paper for more information. You can also find why unsigned integer overflow is not undefined behaviour and what could be portability issues in the same paper.

EDIT:

GCC and other compilers have some provisions to detect the overflow. For example, GCC has following built-in functions allow performing simple arithmetic operations together with checking whether the operations overflowed.

bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
bool __builtin_sadd_overflow (int a, int b, int *res)
bool __builtin_saddl_overflow (long int a, long int b, long int *res)
bool __builtin_saddll_overflow (long long int a, long long int b, long long int *res)
bool __builtin_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
bool __builtin_uaddl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
bool __builtin_uaddll_overflow (unsigned long long int a, unsigned long long int b, unsigned long long int *res)

Visit this link.

EDIT:

Regarding the question asked by someone

I think, it would be nice and informative to explain why signed int overflow undefined, whereas unsigned apperantly isn't..

The answer depends upon the implementation of the compiler. Most C implementations (compilers) just used whatever overflow behaviour was easiest to implement with the integer representation it used.

In practice, the representations for signed values may differ (according to the implementation): one's complement, two's complement, sign-magnitude. For an unsigned type there is no reason for the standard to allow variation because there is only one obvious binary representation (the standard only allows binary representation).

Unsigned integer underflow in C

Firstly, a result that is below the minimum value of the given integer type is not called "underflow" in C. The term "underflow" is reserved for floating-point types and means something completely different. Going out of range of an integer type is always overflow, regardless of which end of the range you cross. So the fact that you don't see the language specification talking about "underflow" doers not really mean anything in this case.

Secondly, you are absolutely right about the meaning of the word "reduced". The final value is defined by adding (or subtracting) UINT_MAX+1 from the "mathematical" result until it returns into the range of unsigned int. This is also the same thing as Euclidean "modulo" operation.

Integer overflow/underflow

I think what you're looking for is

signed char i = -1;
unsigned char j = i;
printf("%u\n", j);

In 8 bits, the signed number -1 "wraps around" to the unsigned value 255.

You asked about size_t because, yes, it's an unsigned type, but it's typically 32 or even 64 bits. At those sizes, the number 255 is representable (and has the same representation) in both the signed and unsigned variants, so there isn't a negative number that corresponds to 255. But you can certainly see similar effects, using different values. For example, on a machine with 32-bit ints, this code:

unsigned int i = 4294967041;
int j = i;
printf("%d\n", j);

is likely to print -255. This value comes about because 2^32 - 255 = 4294967041.



Related Topics



Leave a reply



Submit