-1

I am writing a program in C to calculate the range of different data types. Please look at the following code:

#include <stdio.h>

main()
{
    int a;
    long b;

    for (a = 0; a <= 0; --a)
        ;
    ++a;
    printf("INT_MIN: %d\n", a);
    for (a = 0; a >= 0; ++a)
        ;
    --a;
    printf("INT_MAX: %d\n", a);
    for (b = 0; b <= 0; --b)
        ;
    ++b;
    printf("LONG_MIN: %d\n", b);
    for (b = 0; b >= 0; ++b)
        ;
    --b;
    printf("LONG_MAX: %d\n", b);
}

The output was:

INT_MIN: -32768
INT_MIN: 32767
LONG_MIN: 0
LONT_MAX: -1

The program took a long pause to print the long values. I also put a printf inside the third loop to test the program (not mentioned here). I found that b did not exit the loop even when it became positive.

I used the same method of calculation. Why did it work for int but not for long?

W. Zhu
  • 755
  • 6
  • 16
  • 3
    try `%ld`for `long`, but this is UB. – BLUEPIXY May 05 '16 at 06:39
  • Use `ld` instead of `d` for printing the long int. – G. Emadi May 05 '16 at 06:43
  • 1
    If you are using `gcc` always compile with `-Wall` option. Compiler will give you warnigs about `printf` formats. – LPs May 05 '16 at 06:44
  • 4
    "I am writing a program in C to calculate the range of different data types" - as opposed to, say, including `limits.h` and simply using `LONG_MIN` and `LONG_MAX`? – paxdiablo May 05 '16 at 06:46
  • 2
    signed type overflow invokes undefined behavior – phuclv May 05 '16 at 06:50
  • Little tip: you could code it with 2 loops only, eg: `for (a = 0; a <= 0; --a); printf("INT_MAX: %d\n", a); ++a; printf("INT_MIN: %d\n", a);` – LPs May 05 '16 at 07:05

4 Answers4

3

You are using the wrong format specifier. Since b is of type long, use

printf("LONG_MIN: %ld\n", b);

In fact, if you enabled all warnings, the compiler probably would warn you, e.g:

t.c:19:30: warning: format specifies type 'int' but the argument has type 'long' [-Wformat]
    printf("LONG_MIN: %d\n", b);
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
2

In C it is undefined behaviour to decrement a signed integer beyond its minimum value (and similiarly for incrementing above the maximum value). Your program could do literally anything.

For example, gcc compiles your program to an infinite loop with no output.

The proper approach is:

#include <limits.h>
#include <stdio.h>

int main()
{
    printf("INT_MIN = %d\n", INT_MIN);
    // etc.
}
Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Yes! Why you would want to calculate it at runtime rather than just use what's in `limits.h` is beyond me. – paxdiablo May 05 '16 at 06:48
0

In

printf("LONG_MIN: %d\n", b);

the format specifier is %d which works for integers(int). It should be changed to %ld to print long integers(long) and so is the case with

printf("LONG_MAX: %d\n", b);

These statements should be

printf("LONG_MIN: %ld\n", b);

&

printf("LONG_MAX: %ld\n", b);

This approach may not work for all compilers(eg gcc) and an easier approach would be to use limits.h.

Also check Integer Limits.

sjsam
  • 21,411
  • 5
  • 55
  • 102
0

As already stated, the code you provided invokes undefined behavior. Thus it could calculate what you want or launch nuclear missiles ...

The reason for the undefined behavior is the signed integer overflow that you are provoking in order to "test" the range of the data types.

If you just want to know the range of int, long and friends, then limits.h is the place to look for. But if you really want ...

[..] to calculate the range [..]

... for what ever reason, then you could do so with the unsigned variant of the respective type (though see the note at the end), and calculate the maximum like so:

unsigned long calculate_max_ulong(void) {
  unsigned long follow = 0;
  unsigned long lead = 1;
  while (lead != 0) {
    ++lead;
    ++follow;
  }
  return follow;
}

This only results in an unsigned integer wrap (from the max value to 0), which is not classified as undefined behavior. With the result from above, you can get the minimum and maximum of the corresponding signed type like so:

assert(sizeof(long) == sizeof(unsigned long));
unsigned long umax_h = calculate_max_ulong() / 2u;
long max = umax_h;
long min = - max - 1;

(Ideone link)

Assuming two's complement for signed and that the unsigned type has only one value bit more than the signed type. See §6.2.6.2/2 (N1570, for example) for further information.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • Sorry, the second example is implementation defined. It is not the correct way of getting the max-min values. It will actually cause undefined behavior on certain architectures. – 2501 May 05 '16 at 07:39
  • @2501 Can you point me to the clause in the standard that makes it implementation defined? What do you mean with "not the correct way"? The correct way is - as stated - using limits.h. – Daniel Jour May 05 '16 at 07:47
  • 1
    Even assuming two's complement, the range for the unsigned type may not be exactly twice as big as the corresponding signed type. – 2501 May 05 '16 at 07:50
  • @2501 indeed, the unsigned range may be larger. I didn't know this was possible, so I learned something today. Since I still think my answer provides helpful content I'll keep it, but I added a further note on its limits. – Daniel Jour May 05 '16 at 08:05
  • The same number of value bits will not work, unsigned type must have one more bit than the corresponding signed type if you intend to divide by 2. – 2501 May 05 '16 at 08:07
  • And finally, unlike unsigned types, signed types don't have to have its maximum value to be exactly: 2^n-1. The *only* correct way of obtaining range for signed types is limits.h – 2501 May 05 '16 at 08:11
  • 1
    @2501 I agree that limits.h is the way to go. With the edits my answer should now nonetheless provide useful information (also thanks to this discussion). – Daniel Jour May 05 '16 at 08:20