-1

I am trying to use the strtoul function, but as shown below it is returning an unexpected value (adding ff's in the beginning):

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

main() {
    unsigned long temp ;
    char *err;
    temp = strtoul("3334444444",&err,10);
    if (temp > UINT_MAX) {
        printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
    }else 
        printf("%lx %x\n",temp,3334444444);
}

$./a.out
ffffffffc6bf959c c6bf959c ffffffff 

The above output corresponds to the if part being true, though I expect the else part to get executed here. Can anyone please explain why strtoul is behaving like this? Why does it return ffffffffc6bf959c rather than just c6bf959c? If I use "333444444" (i.e. just one 4 less) rather than "3334444444" in the above code, then I get the correct output (i.e. 13dff55c 13dff55c) corresponding to the else part.

Note : As pointed by melpomene in his reply below, stdlib.h header file should have been included and that will resolve the issue. Can anyone please let me know what is being done by the program by assuming the incorrect return type (int in this case) during compile time which can't be undone (or atleast it is not getting undone in this case) even after knowing the correct return type (unsigned long in this case) during link time ? In short, i want to know how c6bf959c is getting converted to ffffffffc6bf959c because of prototype not provided.

mezda
  • 3,537
  • 6
  • 30
  • 37
  • have you tried strtoull instead of strtoul? – bruceg Jul 18 '16 at 19:47
  • I get your expected behavior with this code. What is your environment? – Christopher Schneider Jul 18 '16 at 19:49
  • `ULONG_MAX` is the same size as `UINT_MAX` on 32-bit systems. `strtoull` would be better, like brueg said. – yellowantphil Jul 18 '16 at 19:51
  • 1
    The maximum value for an unsigned long is 4294967295 so your if condition will be false (evaluate to zero). This may be dependent on your compiler and platdform, I used Oepn Watcom on Windows. When passing a value greater than 4294967295, I get FFFFFFFF. – clarasoft-it Jul 18 '16 at 19:56
  • `3334444444` might be type `unsigned`, `unsigned long` or maybe even `long` (or others). So `"%x"` could be a problem. Recommend `printf("%lx\n",3334444444UL);` and avoid uncertainly. – chux - Reinstate Monica Jul 18 '16 at 20:34

1 Answers1

7

Compiling your code with gcc with warnings enabled gives:

try.c:5:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 main() {
 ^~~~
try.c:5:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
try.c: In function ‘main’:
try.c:8:12: warning: implicit declaration of function ‘strtoul’ [-Wimplicit-function-declaration]
     temp = strtoul("3334444444",&err,10);
            ^~~~~~~
try.c:8:5: warning: nested extern declaration of ‘strtoul’ [-Wnested-externs]
     temp = strtoul("3334444444",&err,10);
     ^~~~
try.c:10:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
         printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
                      ^
try.c:12:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
         printf("%lx %x\n",temp,3334444444);
                      ^

The main problem is implicit declaration of function ‘strtoul’, indicating that the function is not declared (and thus assumed to return int) because you forgot to #include <stdlib.h>. Adding the missing #include fixes the value of temp.

But you should also have a look at the warnings reported for printf and fix those.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • 1
    Also, `temp > UINT_MAX` will never be true on (normal) 32-bit systems. – yellowantphil Jul 18 '16 at 19:52
  • @melpomene : agreed that stdlib.h header file should have been included. Can you please let me know what is being done by the program by assuming the incorrect return value (int in this case) during compile time which can't be undone (or atleast it is not getting undone in this case) even after knowing the correct return value (unsigned long in this case) during link time ? – mezda Jul 18 '16 at 20:16
  • @yellowantphil : can you explain a bit about why it will never be true. temp is a unsigned long and can be greater than uint_max. unsigned long can be 8 bytes on 32 bit system as well. Right ?? – mezda Jul 18 '16 at 20:21
  • @zeebee An unsigned long could be 8 bytes on a 32-bit system, but it's usually 4 bytes, so you can't rely on `strtol` ever returning a number larger than `UINT_MAX`. It's safer to use `strtoll` for that reason. – yellowantphil Jul 18 '16 at 20:24
  • 1
    @zeebee During compile time, code is generated (based on incorrect assumptions about types, registers used, etc). At link time, nothing much happens: Symbol references are resolved to libraries, but the code doesn't change. In particular, the linker knows nothing about types (especially return types). – melpomene Jul 18 '16 at 20:43