Jul 16 2015 • Ender Dai

Definition of INT_MIN

It is well known that a 32bit int can represent integer domain [-2147483648, 2147483647]. Look into /usr/include/limits.h, we can find the definition for constant INT_MIN and INT_MAX:

INT_MAX looks pretty straightforward, but INT_MIN is a little bit weird. Why it is not defined like this:

Well, the question arise because of the wide spread confusion between integer constant and constant expression. The C standard says:

An integer constant begins with a digit, but has no period or exponent part. It may have a prefix that specifies its base and a suffix that specifies its type.

A decimal constant begins with a nonzero digit and consists of a sequence of decimal digits. An octal constant consists of the prefix 0 optionally followed by a sequence of the digits 0 through 7 only. A hexadecimal constant consists of the prefix 0x or 0X followed by a sequence of the decimal digits and the letters a (or A) through f (or F) with values 10 through 15 respectively.

Read it carefully and you will realize that the standard doesn’t mention the sign. So -2147483648 is not an integer constant. Instead, it is a constant expression consisting of unary minus operator - and integer constant 2147483648. To be more clear, the AST (Abstract Syntax Tree) of -2147483648 should be (A) below instead of (B).

Now what do we have? An integer constant 2147483648. This looks suspicious as it is bigger than INT_MAX and can not be represented by int. So what should be its type? The C standard says:

The type of an integer constant is the first of the corresponding list in which its value can be represented.

For unsuffixed decimal, the list is

  • C89: int, long int, unsigned long int
  • C99: int, long int, long long int

So 2147483648 is unsigned long int in C89. The standard also says:

The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

It means the negation of unsigned type is still unsigned. Try this:

Therefore -2147483648 is unsigned long int in C89, which is obviously not what we want.

In C99, 2147483648 is long long int, so -2147483648 is long long int as well, which is also not what we want.

Try this out with both C89 and C99 and see the difference.

Reference

  1. SO question 1 and question 2
  2. http://www.hardtoc.com/archives/119