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
Why Do You Use Typedef When Declaring an Enum in C++
Using Maven for C/C++ Projects
Removing Watermark Out of an Image Using Opencv
Initializing the Size of a C++ Vector
Wrapping C++ Class API for C Consumption
What's the Differences Between .Dll , .Lib, .H Files
C++ Gdb Python Pretty Printing Tutorial
C++ Terminate Called Without an Active Exception
Format Specifiers for Uint8_T, Uint16_T, ...
Why Does This Call the Default Constructor
Should I Inherit from Std::Exception
How to Estimate the Thread Context Switching Overhead
Differencebetween an Empty and a Null Std::Shared_Ptr in C++
Acquire/Release Versus Sequentially Consistent Memory Order
How to Update Gcc in Mingw on Windows