【问题标题】:Parsing a hexadecimal string representation as an integer将十六进制字符串表示解析为整数
【发布时间】:2023-03-25 17:50:01
【问题描述】:

如何将"0000000f" 之类的字符串解析为unsigned long long int?对于较大的值,如何解析像"0000000f,0000000f" 这样分别表示高32位和低32位的字符串?

附:在这个问题中不能使用库函数。

【问题讨论】:

  • 0000000f,0000000f 解析为两个不同的无符号 long long 并在 32 次左移位到第一个之后将它们 ORing 在一起有什么问题?
  • unsigned long long x = strtoull("0000000f", NULL, 16);
  • 在这个问题上我真的不能使用stdlib函数

标签: c algorithm parsing


【解决方案1】:

您可以通过这种方式从<stdlib.h> 使用strtoull()

#include <stdlib.h>

unsigned long long parse_u64(const char *s) {
    unsigned long long v1;

    v1 = strtoull(s, (char **)&s, 16);
    if (*s == ',') {
        v1 = (v1 << 32) | strtoull(s + 1, NULL, 16);
    }
    return v1;
}

请注意,不会检测到格式错误。

如果你不能依赖库函数,使用这个:

int getdigit(int c) {
    if (c >= '0' && c <= '9') return c - '0';
    if (c >= 'a' && c <= 'f') return c - 'a' + 10;
    if (c >= 'A' && c <= 'F') return c - 'A' + 10;
    return -1;
}

unsigned long long parse_u64(const char *s) {
    unsigned long long v1;
    int digit;
    for (v1 = 0; *s; s++) {
        if (*s == ',')
            continue;
        digit = getdigit(*s);
        if (digit < 0)
            break;
        v1 = (v1 << 4) | digit;
    }
    return v1;
}

您可以选择忽略空格和其他字符,或者像我一样停止解析。

【讨论】:

  • 这一行:'unsigned long v1;'应该是:'unsigned long long v1;'
【解决方案2】:

类似于@chqrlie,但有额外的错误检查,

听起来你想要一个字符串到整数的转换。很简单:

unsigned chtohex(char ch) {
  if (ch >= '0' &&  ch <= '9') return ch - '0';
  if (ch >= 'A' &&  ch <= 'Z') return ch - 'A' + 10;
  if (ch >= 'a' &&  ch <= 'a') return ch - 'a' + 10;
  return (unsigned) -1;
}

// return 0 on success,1 on failure
int my_hexstrtoull(const char *s, unsigned long long *dest) {
  unsigned long long sum = 0;
  unsigned ch;
  while (*s) {
    if (*s == ',') continue;
    unsigned ch = chtohex(*s++);
    if (ch >= 16) {
      return 1; // Bad hex char
    }
    if (sum >= ULLONG_MAX/16) {
      return 1; // overflow
    }
    sum = sum * 16 + ch;
    s++;
  }
  *dest = sum;
  return 0;
}

【讨论】:

    【解决方案3】:

    这是一个使用scanf的简单解决方案:

    #include <stdio.h>
    #include <stdlib.h>
    
    unsigned long long int parse(char const * s)
    {
        unsigned long int a, b;
        if (sscanf(s, "%8lx,%8lx", &a, &b) == 2)
            return ((unsigned long long int) a << 32) + b;
        if (sscanf(s, "%8lx", &a) == 1)
            return a;
    
        abort();
    }
    

    【讨论】:

    • 我很欣赏这一点,我应该在原帖中提到它:不能依赖库函数。
    • 第二次调用 scanf 将失败,因为输入流指针已经超过数据。建议保存第一个scanf的返回值。然后如果返回值为1则处理单输入值否则如果输入值为2则处理双输入值否则处理输入失败
    • 建议不要在输入/转换说明符中使用长度修饰符,因为如果输入不是每个数字正好 8 个字节,scanf 就会失败
    • @user3629249:虽然我同意可能不需要最大字段宽度,但它不同于用于指定接收变量大小的 长度修饰符,例如lhllhhL 等。如果十六进制数字较少,8 的最大字段宽度不会导致输入失败,它只会留下任何多余的十六进制数字在输入流中未解析。如果在可选的空白字符字符串之后没有十六进制数字,则会发生输入失败。
    猜你喜欢
    • 2011-04-08
    • 1970-01-01
    • 2015-08-02
    • 1970-01-01
    • 2012-07-07
    • 2012-08-29
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    相关资源
    最近更新 更多