【问题标题】:How to correctly convert a Hex String to Byte Array in C?如何在 C 中正确地将十六进制字符串转换为字节数组?
【发布时间】:2013-08-18 12:50:03
【问题描述】:

我需要将包含十六进制值作为字符的字符串转换为字节数组。尽管已将already here 作为第一个答案,但我收到以下错误:

warning: ISO C90 does not support the ‘hh’ gnu_scanf length modifier [-Wformat]

因为我不喜欢警告,所以省略hh 只会创建另一个警告

warning: format ‘%x’ expects argument of type ‘unsigned int *’, but argument 3 has type ‘unsigned char *’ [-Wformat]

我的问题是:如何正确地做到这一点?为了完成,我在这里再次发布示例代码:

#include <stdio.h>

int main(int argc, char **argv)
{
    const char hexstring[] = "deadbeef10203040b00b1e50", *pos = hexstring;
    unsigned char val[12];
    size_t count = 0;

     /* WARNING: no sanitization or error-checking whatsoever */
    for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) {
        sscanf(pos, "%2hhx", &val[count]);
        pos += 2 * sizeof(char);
    }

    printf("0x");
    for(count = 0; count < sizeof(val)/sizeof(val[0]); count++)
        printf("%02x", val[count]);
    printf("\n");

    return(0);
}

【问题讨论】:

  • 考虑strtol,这可能会有所帮助
  • 没有什么是额外变量解决不了的。

标签: c arrays type-conversion


【解决方案1】:

您可以改用strtol()

只需替换这一行:

sscanf(pos, "%2hhx", &val[count]);

与:

char buf[10];
sprintf(buf, "0x%c%c", pos[0], pos[1]);
val[count] = strtol(buf, NULL, 0);

更新:您可以避免使用sprintf(),而改用此 sn-p:

char buf[5] = {"0", "x", pos[0], pos[1], 0};
val[count] = strtol(buf, NULL, 0);

【讨论】:

  • 更新答案以避免sprintf
  • 您可以将 16 作为 strtol 的第三个参数传递,而不是前缀 "0x"
  • 我用16 为@Vovanium 提到的strtol 解决了这个非常相似的问题,现在我能够像@mvp 提到的那样摆脱sprintf。片段如下所示:char t[5] = {fd, sd, 0}; d[c] = strtol(t, NULL, 16);
【解决方案2】:

您可以将编译器切换到 C99 模式(hh 长度修饰符已在 C99 中标准化),也可以使用 unsigned int 临时变量:

unsigned int byteval;
if (sscanf(pos, "%2x", &byteval) != 1)
{
    /* format error */
}
val[count] = byteval;

【讨论】:

    【解决方案3】:

    为什么不使用 sscanf、strol 等。下面是 HexToBin 和作为免费蜜蜂的 BinToHex。 (注意最初是通过错误记录系统返回的枚举错误代码,而不是简单的 -1 返回。)

    unsigned char HexChar (char c)
    {
        if ('0' <= c && c <= '9') return (unsigned char)(c - '0');
        if ('A' <= c && c <= 'F') return (unsigned char)(c - 'A' + 10);
        if ('a' <= c && c <= 'f') return (unsigned char)(c - 'a' + 10);
        return 0xFF;
    }
    
    int HexToBin (const char* s, unsigned char * buff, int length)
    {
        int result;
        if (!s || !buff || length <= 0) return -1;
    
        for (result = 0; *s; ++result)
        {
            unsigned char msn = HexChar(*s++);
            if (msn == 0xFF) return -1;
            unsigned char lsn = HexChar(*s++);
            if (lsn == 0xFF) return -1;
            unsigned char bin = (msn << 4) + lsn;
    
            if (length-- <= 0) return -1;
            *buff++ = bin;
        }
        return result;
    }
    
    void BinToHex (const unsigned char * buff, int length, char * output, int outLength)
    {
        char binHex[] = "0123456789ABCDEF";
    
        if (!output || outLength < 4) return;
        *output = '\0';
    
        if (!buff || length <= 0 || outLength <= 2 * length)
        {
            memcpy(output, "ERR", 4);
            return;
        }
    
        for (; length > 0; --length, outLength -= 2)
        {
            unsigned char byte = *buff++;
    
            *output++ = binHex[(byte >> 4) & 0x0F];
            *output++ = binHex[byte & 0x0F];
        }
        if (outLength-- <= 0) return;
        *output++ = '\0';
    }
    

    【讨论】:

      【解决方案4】:

      使用 mvp 的建议更改,我创建了这个函数,其中包括错误检查(无效字符和不均匀长度)。

      此函数会将偶数个字符的十六进制字符串(不以“0x”开头)转换为指定的字节数。如果遇到无效字符,或者十六进制字符串的长度为奇数,它将返回 -1,成功则返回 0。

      //convert hexstring to len bytes of data
      //returns 0 on success, -1 on error
      //data is a buffer of at least len bytes
      //hexstring is upper or lower case hexadecimal, NOT prepended with "0x"
      int hex2data(unsigned char *data, const unsigned char *hexstring, unsigned int len)
      {
          unsigned const char *pos = hexstring;
          char *endptr;
          size_t count = 0;
      
          if ((hexstring[0] == '\0') || (strlen(hexstring) % 2)) {
              //hexstring contains no data
              //or hexstring has an odd length
              return -1;
          }
      
          for(count = 0; count < len; count++) {
              char buf[5] = {'0', 'x', pos[0], pos[1], 0};
              data[count] = strtol(buf, &endptr, 0);
              pos += 2 * sizeof(char);
      
              if (endptr[0] != '\0') {
                  //non-hexadecimal character encountered
                  return -1;
              }
          }
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2017-06-17
        • 1970-01-01
        • 1970-01-01
        • 2011-09-15
        • 2012-04-11
        • 2019-03-07
        • 2013-01-14
        • 2017-08-23
        • 2011-01-10
        相关资源
        最近更新 更多