【问题标题】:Convert hexadecimal string to long将十六进制字符串转换为长字符串
【发布时间】:2012-07-22 14:37:20
【问题描述】:

我正在尝试在 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.将基数设置为 0 意味着 strtol 会尝试从输入字符串的开头自行计算,是否使用基数 16、10 或 8。
  • 对,我忘了!谢谢!

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


【解决方案1】:

long 的最小范围是 -2147483647 到 2147483647。您的实现中 long 的范围可能是 -2147483648 到 2147483647。

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

顺便说一句,您对sscanf() 的调用是用sscanf() 的返回值覆盖n 中的转换值,即1 表示转换成功。

【讨论】:

    【解决方案2】:

    如果您不想要溢出效果,请不要使用该函数的有符号变体。请改用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。 :)
    • @juampa 溢出发生在函数内部,我相信。为什么会有两个函数?但是,如果您将 'n' 的内容输出为已签名,您将得到 -60876...meh,他的编辑击败了我:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 1970-01-01
    • 2018-01-31
    • 2013-05-10
    • 2013-02-07
    相关资源
    最近更新 更多