I have below a simple program:
#include <stdio.h>
#define INT32_MIN (-0x80000000)
int main(void)
{
long long bal = 0;
if(bal < INT32_MIN )
{
printf("Failed!!!");
}
else
{
printf("Success!!!");
}
return 0;
}
The condition if(bal < INT32_MIN )
is always true. How is it possible?
It works fine if I change the macro to:
#define INT32_MIN (-2147483648L)
Can anyone point out the issue?
This is quite subtle.
Every integer literal in your program has a type. Which type it has is regulated by a table in 6.4.4.1:
If a literal number can't fit inside the default
int
type, it will attempt the next larger type as indicated in the above table. So for regular decimal integer literals it goes like:int
long
long long
.Hex literals behave differently though! If the literal can't fit inside a signed type like
int
, it will first tryunsigned int
before moving on to trying larger types. See the difference in the above table.So on a 32 bit system, your literal
0x80000000
is of typeunsigned int
.This means that you can apply the unary
-
operator on the literal without invoking implementation-defined behavior, as you otherwise would when overflowing a signed integer. Instead, you will get the value0x80000000
, a positive value.bal < INT32_MIN
invokes the usual arithmetic conversions and the result of the expression0x80000000
is promoted fromunsigned int
tolong long
. The value0x80000000
is preserved and 0 is less than 0x80000000, hence the result.When you replace the literal with
2147483648L
you use decimal notation and therefore the compiler doesn't pickunsigned int
, but rather tries to fit it inside along
. Also the L suffix says that you want along
if possible. The L suffix actually has similar rules if you continue to read the mentioned table in 6.4.4.1: if the number doesn't fit inside the requestedlong
, which it doesn't in the 32 bit case, the compiler will give you along long
where it will fit just fine.