Jayesh - 3 months ago 18
C Question

# Why is 0 < -0x80000000?

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:

``````Suffix      Decimal Constant    Octal or Hexadecimal Constant

none        int                 int
long int            unsigned int
long long int       long int
unsigned long int
long long int
unsigned long long int
``````

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:

• Try `int`
• If it can't fit, try `long`
• If it can't fit, try `long long`.

Hex literals behave differently though! If the literal can't fit inside a signed type like `int`, it will first try `unsigned 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 type `unsigned 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 value `0x80000000`, a positive value.

`bal < INT32_MIN` invokes the usual arithmetic conversions and the result of the expression `0x80000000` is promoted from `unsigned int` to `long long`. The value `0x80000000` 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 pick `unsigned int`, but rather tries to fit it inside a `long`. Also the L suffix says that you want a `long` 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 requested `long`, which it doesn't in the 32 bit case, the compiler will give you a `long long` where it will fit just fine.

Source (Stackoverflow)