如何将十六进制字符串转换为 uint8_t 数组? (C语言)

How to convert a hex string to a uint8_t array? (C language)

如何将十六进制字符串转换为 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};

感谢您的帮助!

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

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

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

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

然后如何合并,第一个值需要向上(向左)移动四位,然后与第二个值按位或。

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

您可以使用 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] = '[=11=]';
        if (*src) {
            buf[1] = *src++;
            buf[2] = '[=11=]';
        }
        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] = '[=12=]';
        if (*src) {
            buf[1] = *src++;
            buf[2] = '[=12=]';
        }
        if (sscanf(buf, "%hhx", &dest[i]) != 1)
            break;
    }
    return i;
}

纯粹主义者可能会争辩说 %hhx 需要一个指向 unsigned char 而不是 uint8_t 的指针,因此格式应该是 "%"SCNx8"%2"SCNx8,已定义在 <inttypes.h> 中,但这些替代方案的可读性较差且不必要,因为类型 uint8_t 在其定义的体系结构上始终与类型 unsigned char 相同。

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'10、...