Convert hexadecimal string to long

jpmuc picture jpmuc · Jul 24, 2012 · Viewed 8.2k times · Source

I am trying to do an hexadecimal to integer conversion on a 32 bit machine. Here is the code I am testing with,

int main(int argc,char **argv)
{
    char *hexstring = "0xffff1234";
    long int n;

    fprintf(stdout, "Conversion results of string: %s\n", hexstring);
    n = strtol(hexstring, (char**)0, 0); /* same as base = 16 */
    fprintf(stdout, "strtol = %ld\n", n);
    n = sscanf(hexstring, "%x", &n);
    fprintf(stdout, "sscanf = %ld\n", n);
    n = atol(hexstring);
    fprintf(stdout, "atol = %ld\n", n);
    fgetc(stdin);

    return 0;
  }

This is what I get:

 strtol = 2147483647 /* = 0x7fffffff -> overflow!! */
 sscanf = 1 /* nevermind */
 atol = 0   /* nevermind */

As you see, with strtol I get an overflow (I also checked with errno), although I would expect none to happen, since 0xffff1234 is a valid integer 32bit value. I would either expect 4294906420 or else -60876

What am I missing?

Answer

paxdiablo picture paxdiablo · Jul 24, 2012

If you don't want the overflow effect, don't use the signed variant of the function. Use strtoul() instead.

With the following code:

#include <stdio.h>
int main(int argc,char **argv) {
    char *hexstring = "0xffff1234";
    long sn;
    unsigned long un;

    fprintf(stdout, "Conversion results of string: %s\n", hexstring);

    sn = strtoul(hexstring, (char**)0, 0);
    fprintf(stdout, "strtoul   signed = %ld\n", sn);

    un = strtoul(hexstring, (char**)0, 0);
    fprintf(stdout, "strtoul unsigned = %lu\n", un);

    return 0;
}

I get:

Conversion results of string: 0xffff1234
strtoul   signed = -60876
strtoul unsigned = 4294906420

You cannot control this when calling strtol() and its brethren since the behaviour is within those functions. The standard has this to say:

The strtol, strtoll, strtoul, and strtoull functions return the converted value, if any. If no conversion could be performed, zero is returned. If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any), and the value of the macro ERANGE is stored in errno.