将十六进制字符串转换为long

时间:2012-07-24 09:39:58

标签: c hex type-conversion integer-overflow strtol

我试图在32位机器上进行十六进制到整数转换。这是我正在测试的代码,

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;
  }

这就是我得到的:

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

如你所见,使用strtol我得到溢出(我也检查过errno),虽然我不希望发生任何事情,因为0xffff1234是一个有效的整数32位值。 我要么期望4294906420,要么是-60876

我错过了什么?

2 个答案:

答案 0 :(得分:6)

如果您不想要溢出效果,请不要使用该功能的已签名变体。请改用strtoul()

使用以下代码:

#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;
}

我明白了:

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

在调用strtol()及其兄弟时,您无法控制此行为,因为行为 这些函数。标准有这样说:

  

strtol,strtoll,strtoul和strtoull函数返回转换后的值(如果有)。如果无法执行转换,则返回零。如果正确的值超出可表示值的范围,则返回LONG_MIN,LONG_MAX,LLONG_MIN,LLONG_MAX,ULONG_MAX或ULLONG_MAX(根据值的返回类型和符号,如果有),并且宏ERANGE的值为存储在errno。

答案 1 :(得分:3)

long的最小范围是-2147483647到2147483647.您实施的long范围可能是-2147483648到2147483647.

strtol()的定义表示如果转换后的值超出long的范围,则会根据转换后的值的符号返回LONG_MINLONG_MAXERANGE存储在errno中。在这种情况下,转换后的值0xffff1234超出了范围 - 它大于LONG_MAX,因此会返回LONG_MAX

顺便说一下,您对sscanf()的调用会覆盖n中转换后的值,返回值为sscanf(),该值为1,表示转换成功1次。