-2

I am trying to print the value of a particularly large value after reading it from the console. When I am trying to print it from two different ways, one directly after assigning, one with the return value from the strtol function, I get different output! Can someone please explain me why I am noticing two different outputs?

Input value is: 4294967290

Here is the code snippet.

long int test2 = strtol(argv[1], &string, 10);
printf("the strtol value is %ld\n", test2);
printf("the strtol function value is %ld\n", strtol(argv[1], &string, 10));

Output

the strtol value is -6
the strtol function value is 4294967290
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Coder
  • 1,415
  • 2
  • 23
  • 49
  • "PS: Pls point me if this question has already been answered. Thanks!" That is research you should already have done before you posted the question – Chris Beck Sep 13 '15 at 02:43
  • The posted code looks ok to me. – R Sahu Sep 13 '15 at 02:46
  • 2
    To me it is the same. I think there is a problem in other parts – BLUEPIXY Sep 13 '15 at 02:52
  • 4
    I can’t reproduce this. Could you please provide a complete example? Are you sure `test2` is declared as a `long int`? It looks like it’s 32 bits and `long int` is more. – Ry- Sep 13 '15 at 02:52
  • It coundn't be reproduced in [Wandbox](http://melpon.org/wandbox/permlink/72bfWtPWEHUM05fG) and [Ideone](https://ideone.com/G4tsxZ). What is your compiler? – MikeCAT Sep 13 '15 at 02:59
  • Are you compiling in an environment where long is 32 bit but linking with a library where long is 64 bit? – headuck Sep 13 '15 at 03:16
  • 1
    Frankly, I don't believe that's the output you see — or, if it is, then the code you show isn't the code you execute. Which machine are you on? Are you dealing with 32-bit or 64-bit code? – Jonathan Leffler Sep 13 '15 at 03:50
  • @JonathanLeffler: it's easy enough to reproduce. http://coliru.stacked-crooked.com/a/cb9ae7594f8a8edb – rici Sep 13 '15 at 04:29
  • @rici: 64-bit little-endian Unix system, and invoking undefined behaviour? _[…time passes…]_ Hmmm; if you don't include `` then you're invoking undefined behaviour too. Well, I certainly assumed that the code was being compiled under C99 or C11 rules — not under sloppy old C89/C99 rules. Grrr! – Jonathan Leffler Sep 13 '15 at 04:41
  • @JonathanLeffler: 64-bit little-endian Unix-like systems are pretty common, I think :) And you can tell gcc `-std=c99`; it will still just produce a warning or three. There's probably a canonical "you forgot to declare the library function" question somewhere waiting to be used as a dup... (There is no other UB in that snippet, is there? With the right includes, it should be fine.) – rici Sep 13 '15 at 04:50

1 Answers1

2

You need to do two things:

  1. Add the line #include <stdlib.h> at the beginning of your program. That will cause strtol to be declared. (You also need #include <stdio.h> in order to declare printf.)

  2. Add -Wall to your compiler flags (if you are using gcc or clang). That will cause the compiler to tell you that you need to declare strtol, and it might even suggest which header to include.

What is going on is that you haven't declared strtol, with the result that the compiler assumes that it returns an int.

Since 4294967290 is 232-6, it is the 32-bit Two's-complement representation of -6. Because the compiler assumes that strtol returns an int, the code it produces only looks at the low-order 32 bits. Since you are assigning the value to a long, the compiler needs to emit code which sign-extends the int. In other words, it takes the low-order 32 bits as though they were a signed integer (which would be -6) and then widens that -6 to a long.

In the second call to printf, the return value of strtol is inserted in the printf argument list without conversion. You tell printf that the argument is a long (by using the l flag in %ld), and by luck the entire 64 bits are in the argument list, so printf reads them out as a long and prints the "correct" value.

Needless to say, all this is undefined behaviour, and the actual output you are seeing is in no way guaranteed; it just happens to work that way with your compiler on your architecture. On some other compiler or on some other architecture, things might have been completely different, including the bit-length of int and long. So the above explanation, although possibly interesting, is of no practical value. Had you simply included the correct header and thereby told the compiler the real return type of strtol, you would have gotten the output you expected.

rici
  • 234,347
  • 28
  • 237
  • 341