将十六进制字符串转换为长整型

3

我正在尝试在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。
我错在哪里了?

你确定将基数设置为0和16是一样的吗?我的意思是将strtol(hexstring, (char)0, 0) 替换为 strtol(hexstring, (char*)0, 16)*。 - A.G.
@A.G. 将基数设置为0意味着strtol会尝试从输入字符串的开头自行确定使用基数16、10还是8。 - Daniel Fischer
2个回答

7
如果您不希望出现溢出效果,请勿使用函数的有符号版本,可以使用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中。

那是正确的解决方案,没错。唉,我把它放在文档前面,但没有看到它:D 无论如何+1。 :) - ATaylor
@juampa 溢出发生在函数内部,我相信。否则为什么会有两个函数呢?然而,如果你将 'n' 的内容输出为有符号数,你会得到 -60876...嗯,他的编辑比我快 :D - ATaylor

3
long的最小范围为-2147483647到2147483647。在你的实现中,long的范围可能为-2147483648到2147483647。 strtol()的定义指出,如果转换后的值超出了long的范围,则根据转换后的值的符号返回LONG_MINLONG_MAX,并将ERANGE存储在errno中。在这种情况下,转换后的值 0xffff1234 超出了范围 - 它大于LONG_MAX,因此返回LONG_MAX
顺便说一下,你对sscanf()的调用会覆盖n中的转换后的值,并用sscanf()的返回值1进行覆盖,表示成功转换了1次。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接