You need to do two things:
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
.)
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.