No, your 2nd code isn't correct, but you are close: if you set
int half = INT_MAX/2;
int half1 = half + 1;
the result of an addition is INT_MAX
. (INT_MAX
is always an odd number). So this is valid input. But in your routine you will have INT_MAX - half == half1
and you would abort. A false positive.
This error can be repaired by putting <
instead of <=
in both checks.
But then also your code isn't optimal. The following would do:
int add(int lhs, int rhs)
{
if (lhs >= 0) {
if (INT_MAX - lhs < rhs) {
/* would overflow */
abort();
}
}
else {
if (rhs < INT_MIN - lhs) {
/* would overflow */
abort();
}
}
return lhs + rhs;
}
To see that this is valid, you have to symbolically add lhs
on both sides of the inequalities, and this gives you exactly the arithmetical conditions that your result is out of bounds.
Note in 2023: C23 will have the <stdckdint.h>
header that implements such overflow checks in the same way as the gcc builtins that are mentioned in other answers.
is still overflow of these types an undefined behavior?
Yes. Per Paragraph 5/4 of the C++11 Standard (regarding any expression in general):
If during the evaluation of an expression, the result is not mathematically defined or not in the range of
representable values for its type, the behavior is undefined. [...]
The fact that a two's complement representation is used for those signed types does not mean that arithmetic modulo 2^n is used when evaluating expressions of those types.
Concerning unsigned arithmetic, on the other hand, the Standard explicitly specifies that (Paragraph 3.9.1/4):
Unsigned integers, declared unsigned
, shall obey the laws of arithmetic modulo 2^n where n is the number
of bits in the value representation of that particular size of integer
This means that the result of an unsigned arithmetic operation is always "mathematically defined", and the result is always within the representable range; therefore, 5/4 does not apply. Footnote 46 explains this:
46) This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting
unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the
resulting unsigned integer type.
Best Answer
Both references are correct, but they do not address the same issue.
int a = UINT_MAX;
is not an instance of signed integer overflow, this definition involves a conversion fromunsigned int
toint
with a value that exceeds the range of typeint
. As quoted from the École polytechnique's site, the C Standard defines the behavior as implementation-defined.Here is the text from the C Standard:
Some compilers have a command line option to change the behavior of signed arithmetic overflow from undefined behavior to implementation-defined:
gcc
andclang
support-fwrapv
to force integer computations to be performed modulo the 232 or 264 depending on the signed type. This prevents some useful optimisations, but also prevents some counterintuitive optimisations that may break innocent looking code. See this question for some examples: What does -fwrapv do?