问题
I'm running a C++ program which adds numbers in a for loop:
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
}
but I am not sure how to check if an overflow has occured. Is there a way?
回答1:
Overflow of a signed integral variable results in undefined behaviour. A consequence is that, once overflow has occurred, it cannot be reliably detected in standard C++. Any behaviour is permitted. So your implementation (compiler, library, toolset, etc) may provide a specific means to detect integer overflow - but that means will not necessarily work with other implementations.
The only ways are to check for potential overflows before doing operations (or a sequence of operations). Or to design your approach (e.g. pick limits) to prevent overflow occurring.
回答2:
There are different options and probably no one that suits every situation and need.
For example in this situation you could check that if pow
is less or equal to INT_MAX/10
before multiplying. This works because INT_MAX/10
is the largest number such that it times 10 will be at most INT_MAX
. Note that the compiler would normally precompute the INT_MAX/10
if you insert it into the code (otherwise you could put it in a local variable if it bothers you):
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
}
This solution has the disadvantage that if the other factor is not constant the compiler (and you) can't reasonably avoid the division INT_MAX/n
to be done at runtime (and division is normally more expensive than multiplication).
Another possibility is that you could do the calculation in a wider type. For example:
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
}
This have the disadvantage that first a wider type might not be available, and if it is it may require software implementation of the multiplication (for example 64-bit on 32-bit systems) which means slower multiplication.
Another situation is where you add two integers. If overflow occurs the result will be less than both integers, especially if they're both positive the result will be negative.
回答3:
As Peter rightly explained, overflow is undefined behavior in standard C++11 (or C99), and you really should be afraid of UB.
However, some compilers give you extensions to deal and detect integer overflow.
If you can restrict yourself to a recent GCC compiler, you could use its integer overflow builtins.
You could also restrict yourself to int32_t
and compute arithmetic in int64_t
and check against result above INT32_MAX
or below INT32_MIN
. This would be probably slower (but more portable) than using compiler specific extensions. BTW some compilers also have some __int128_t
type (so you could compute arithmetic in __int128_t
and check likewise that the result fits in int64_t
).
If your goal is to have arbitrary precision arithmetic, better use some exising bignum library, like GMPlib (because efficient bignum arithmetic needs very clever algorithms).
来源:https://stackoverflow.com/questions/33185621/check-for-int-overflow-in-c