While adding a few header files to WCRT (a small C runtime library for Visual C++), I stumbled upon something that caught my interest.

`INT_MIN` in <limits.h> is a macro that expands to the minimum value for an object of type int. In the 32-bit C compilers I have installed at the moment, it is defined as:

1 |
#define INT_MIN (-2147483647 - 1) |

So what exactly is wrong with the integer constant -2147483648 ?

Well, firstly it is not an integer constant. Let’s see what the 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.”

You will notice there is no mention of a sign. So -2147483648 is in fact a constant expression, consisting of the unary minus operator, and the integer constant 2147483648.

This still does not explain why that expression is not used directly in the macro. To see that, we have to revisit the rules for the type of integer constants.

The type of an unsuffixed integer constant is the first of these in which its value can be represented:

C89 | : | int, long int, unsigned long int |
---|---|---|

C99 | : | int, long int, long long int |

C++ | : | int, long int, long long int |

The problem is that 2147483648 cannot be represented in a signed 32-bit integer, so it becomes either an unsigned long int or a long long int.

So we have to resort to a little trickery, and compute -2147483648 as (-2147483647 – 1), which all fit nicely into 32-bit signed integers, and `INT_MIN` gets the right type and value.

If you happen to look up `INT_MIN` in the standard you will see:

minimum value for an object of type int

1 INT_MIN -32767

Which brings up the question why isn’t it (-32767 – 1)?

Pretty much any computer available today uses two’s complement to represent signed numbers, but this hasn’t always been the case.

Since C was designed to work efficiently on a variety of architectures, the standard’s limits allow for using other representations as well.

I will end this post with a little (not quite standard conformant) example. Try compiling it with your favorite C compiler, and let us know if something puzzles you.

1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <stdio.h> #include <limits.h> #include <float.h> int main(void) { if (-2147483648 > 0) printf("positive\n"); if (-2147483647 - 1 < 0) printf("negative\n"); if (INT_MIN == -INT_MIN) printf("equal\n"); if (FLT_MIN > 0) printf("floating\n"); return 0; } |