Home > Mobile >  Why this strange values are returned form calling <limits.h> definitios?
Why this strange values are returned form calling <limits.h> definitios?

Time:11-27

I do not understand why these strange values are returned from LONG_MAX, LONG_MIN and UINT_MAX. Furthermore, since I am following the book "The C programming Languege", I noticed that the values of the range of int in my pc are precisely the one of the long in the book. Is this even possible?

SOURCE CODE:

int main(){
printf(" [INT]\t|%d | %d|\n", INT_MAX, INT_MIN);
printf("[UINT]\t|d| d|\n", UINT_MAX);
printf("[SHRT]\t|d| d|\n", SHRT_MAX, SHRT_MIN);
printf("[LONG]\t|d| d|\n", LONG_MAX, LONG_MIN);
}

OUTPUT:

 [INT]  |2147483647 | -2147483648|
[UINT]  |         -1|           0|
[SHRT]  |      32767|      -32768|
[LONG]  |         -1|           0|

CodePudding user response:

LONG_MAX and LONG_MIN should be printed using %ld (or ld or similarly) because their type is long. When they are printed with %d, the behavior is not defined by the C standard, and the program may misbehave in various ways.

UINT_MAX should be printed using %u (or u or similarly) because its type is unsigned int.

Also, printf("[UINT]\t|d| d|\n", UINT_MAX); has two conversion specifications but only one value supplied. Either add another argument, or remove the second conversion specification.

CodePudding user response:

The values are not correct for UINT_MAX, LONG_MAX and for LONG_MIN. The others are correct (maximal and minimal values of the signed integers).

UINT_MAX is defined in limits.h (or in another header file included by it) roughly so:

#define UINT_MAX 4294967295

It is handled by the C preprocessor. Effectively, any time if you use UINT_MAX in your C code, the 4294967295 substituted in it, as a string.

Thus, your relevant code line will be preprocessed to

printf("[UINT]\t|d| d|\n", 4294967295, 0);

If there is no other advice, this large 4294967295 will be interpreted as a signed integer. But it is too big for a signed integer, as their maximum is about 2billion. This makes an integer overflow bug (the standard calls it "undefined behavior" or so, but our language lawyers will likely correct me soon). But the bit field of 4294967295, interpreted as a signed integer, is exactly -1.

The simplest workaround is to advice the compiler to interpret the variable as an unsigned integer, roughly so:

printf("[UINT]\t|d| d|\n", 4294967295UL, 0);

This is still not okay, because %d expects a signed integer, so also fix the formatting string. Possibly %D or %Ld will be what you need, check the docs and turn on all warnings.

Because C is (intentionally) weak in type checking, it is good advice to turn on all possible warnings (in gcc, -Wall flag) and write always clean, warning-less code. Do not even try to start a code if it is not purely warning-free - it is much easier to solve warnings than mysterious bugs.

P.s. in theory, the C standard does not describe the bit length of the integer types, possibly not even their bit-level representation, so a huge language lawyering is possible around this topic, and it will likely happen.

  •  Tags:  
  • c
  • Related