#c #type-conversion #hex #uint8t #uint8array
Вопрос:
как я могу преобразовать шестнадцатеричную строку в массив 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};
Спасибо вам за вашу помощь!
Ответ №1:
Вы можете использовать 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 amp;amp; sscanf(src i * 2, "%2x", amp;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 amp;amp; *src; i ) {
buf[0] = *src ;
buf[1] = '';
if (*src) {
buf[1] = *src ;
buf[2] = '';
}
if (sscanf(buf, "%x", amp;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 amp;amp; *src; i ) {
buf[0] = *src ;
buf[1] = '';
if (*src) {
buf[1] = *src ;
buf[2] = '';
}
if (sscanf(buf, "%hhx", amp;dest[i]) != 1)
break;
}
return i;
}
Пуристы могут утверждать , что %hhx
ожидает указатель на an unsigned char
вместо a uint8_t
, поэтому формат должен быть "%"SCNx8
или "%2"SCNx8
, определенным в <inttypes.h>
, но эти альтернативы менее удобочитаемы и не нужны, поскольку тип uint8_t
всегда идентичен типу unsigned char
в архитектурах, где он определен.
Комментарии:
1. большое вам спасибо! знаете ли вы, как распечатать массив uint8_t? если я выполняю printf(«%d», myarray[0]), он выводит десятичное значение первого элемента myarray. как я могу напечатать точный элемент (например, 0xFF)?
2. @WonderWhy: десятичные и шестнадцатеричные числа-это просто представления точного значения… Используется
printf("0xX", myarray[0])
для получения шестнадцатеричного представления с0x
префиксом. Удалите0x
, чтобы получить только 2 шестнадцатеричных байта.
Ответ №2:
Первое, что вам нужно усвоить, — это то, что десятичные, шестнадцатеричные или даже восьмеричные числа-это то, как представлены двоичные числа, хранящиеся в памяти компьютера. Как только вы сохраните байты в своем массиве, они больше не будут шестнадцатеричными.
Теперь о том, как решить вашу проблему: вам нужно извлечь два символа одновременно, затем преобразовать каждый символ в соответствующее целочисленное значение и использовать бит-рубашку и бит-или объединить их в однобайтовое значение.
Преобразование цифр 0
9
в их соответствующее значение легко, так как в спецификации C говорится, что они должны быть закодированы последовательно (т. Е. '0'
должны поступать непосредственно перед '1'
и так далее). Это означает, что вы можете использовать простое вычитание, '0'
чтобы получить числовое значение ( '0' - '0' == 0
и '1' - '0' == 1
т. Д.).
Буквы A
F
, которые нужно прочитать, сложнее, потому что существует множество различных возможных кодировок, в том числе некоторые, которые не размещают буквы последовательно. С учетом сказанного, наиболее распространенной кодировкой ASCII является выполнение этого, что означает, что в большинстве систем вы можете использовать тот же «трюк», что и для десятичных цифр.
Затем, как их объединить, первое значение должно быть сдвинуто вверх (влево) на четыре бита, а затем растрировано ИЛИ дополнено вторым значением.
Результатом этого должен быть один байт, значение которого совпадает с двумя шестнадцатеричными цифрами из строки. Добавьте это значение в массив.
Комментарии:
1. Вероятно, мой вопрос был совсем не ясен, и я прошу прощения за это. Мне нужно только время от времени извлекать символы из строки и помещать их в массив uint8_t. Например, мой пустой массив-uint8_t myarray = {}, я извлекаю «02» из строки и добавляю их в myarray, это будет myarray ={ 0x02 }
2. Стандартная функция strtol на языке Си может быть полезна, но затем вы будете использовать временную строку с нулевым окончанием, в которую вы копируете два символа одновременно.
Ответ №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'
в 10
,…