【问题标题】:How to convert a hex string to a uint8_t array? (C language)如何将十六进制字符串转换为 uint8_t 数组? (C语言)
【发布时间】:2021-11-05 23:43:09
【问题描述】:

如何将十六进制字符串转换为 uint8_t 数组? 我的字符串是02012B1530A6E3958A98530031902003876940000000000CDF9844173BE512AFFFFFFE11DBBA1F00079387800E13012E11FC017FFFFFFFFE39C10F40 我想把它转换成这个数组:

uint8_t array_uint[] = {0x02, 0x01, 0x2B, 0x15, 0x30, 0xA6, 0xE3, 0x95, 0x8A, 0x98, 0x53, 0x00, 0x31, 0x90, 0x20, 0x03, 0x87, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xDF, 0x98, 0x44, 0x17, 0x3B, 0xE5, 0x12, 0xAF, 0xFF, 0xFF, 0xFE, 0x11, 0xDB, 0xBA, 0x1F, 0x00, 0x07, 0x93, 0x87, 0x80, 0x0E, 0x13, 0x01, 0x2E, 0x11, 0xFC, 0x01, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x39, 0xC1, 0x0F, 0x40};

感谢您的帮助!

【问题讨论】:

    标签: c type-conversion hex uint8t uint8array


    【解决方案1】:

    您需要了解的第一件事是,十进制、十六进制甚至八进制正是存储在计算机内存中的二进制数字的呈现方式。一旦将字节存储在数组中,它们就不再是真正的十六进制了。

    现在如何解决你的问题:你需要一次提取两个字符,然后将每个字符转换为对应的整数值,并使用bit-shirt和bit-or将它们组合成一个字节值。

    将数字 0 转换为 9 到它们对应的值很容易,因为 C 规范规定它们必须连续编码(即 '0' 必须紧挨在 '1' 之前,等等)。这意味着您可以使用与'0' 的简单减法来获得数值('0' - '0' == 0'1' - '0' == 1 等)。

    字母AF 更难通过,因为有许多不同的可能编码,包括一些不连续放置字母的编码。话虽如此,最常见的 ASCII 编码 do 就是这样做的,这意味着在大多数系统上,您可以使用与十进制数字相同的“技巧”。

    然后如何组合它们,第一个值需要上移(向左)四位,然后与第二个值进行按位或运算。

    结果应该是一个字节,其值与字符串中的两个十六进制数字相同。将此值附加到数组中。

    【讨论】:

    • 可能我的问题根本不清楚,对此我深表歉意。我只需要从字符串中提取字符并将其放入 uint8_t 数组中。例如,我的空数组是 uint8_t myarray = {},我从字符串中提取“02”并将它们添加到 myarray,即 myarray ={ 0x02 }
    • 标准 C 函数 strtol 可能会有所帮助,但您将使用一个临时的以零结尾的字符串,一次复制两个字符。
    【解决方案2】:

    您可以使用 sscanf() 一次将 2 个字节从源字符串转换为目标数组:

    #include <stdint.h>
    #include <stdio.h>
    
    size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
        size_t i;
        int value;
        for (i = 0; i < count && sscanf(src + i * 2, "%2x", &value) == 1; i++) {
            dest[i] = value;
        }
        return i;
    }
    

    但是请注意,在标准库为每次调用 sscanf() 计算源字符串长度的架构上,这种方法可能效率低下,时间复杂度为二次方。使用中间数组解决了这个问题:

    #include <stdint.h>
    #include <stdio.h>
    
    size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
        char buf[3];
        size_t i;
        int value;
        for (i = 0; i < count && *src; i++) {
            buf[0] = *src++;
            buf[1] = '\0';
            if (*src) {
                buf[1] = *src++;
                buf[2] = '\0';
            }
            if (sscanf(buf, "%x", &value) != 1)
                break;
            dest[i] = value;
        }
        return i;
    }
    

    将转换结果直接存入dest数组很简单:

    #include <stdint.h>
    #include <stdio.h>
    
    size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
        char buf[3];
        size_t i;
        for (i = 0; i < count && *src; i++) {
            buf[0] = *src++;
            buf[1] = '\0';
            if (*src) {
                buf[1] = *src++;
                buf[2] = '\0';
            }
            if (sscanf(buf, "%hhx", &dest[i]) != 1)
                break;
        }
        return i;
    }
    

    纯粹主义者可能会争辩说%hhx 需要一个指向unsigned char 而不是uint8_t 的指针,因此格式应该是"%"SCNx8"%2"SCNx8,在&lt;inttypes.h&gt; 中定义,但这些替代方案的可读性和可读性较差不必要,因为类型 uint8_t 总是与类型 unsigned char 在定义它的架构上相同。

    【讨论】:

    • 非常感谢!你知道如何打印 uint8_t 数组吗?如果我执行 printf("%d", myarray[0]) 它会打印 myarray 的第一个元素的十进制值。如何打印确切的元素(例如 0xFF)?
    • @WonderWhy: decimal 和 hexadecimal 只是 exact 值的表示...使用 printf("0x%02X", myarray[0]) 获得带有 0x 前缀的十六进制表示。删除 0x 以仅获取 2 个十六进制字节。
    【解决方案3】:

    char data[] = "02012B1530A6E3958A98530031902003876940000000000CDF9844173BE512AFFFFFFE11DBBA1F00079387800E13012E11FC017FFFFFFFFE39C10F40";
    char *p = data;
    

    第一个字节是

    (hexdigit(p[0]) << 4) + hexdigit(p[1])
    

    你可以用

    循环上面的表达式
    do {
        uint8_t value = (hexdigit(p[0]) << 4) + hexdigit(p[1]);
        p += 2;
    } while (*p);
    

    对于所有值(确保data 有偶数个字符)。

    函数hexdigit()(实现留作练习)将'0'转换为0'1'转换为1,...,'a'转换为10'A'转换为@ 987654333@, ...

    【讨论】:

      猜你喜欢
      • 2020-11-15
      • 2019-06-05
      • 1970-01-01
      • 1970-01-01
      • 2018-01-31
      • 1970-01-01
      • 2014-03-19
      相关资源
      最近更新 更多