Преобразовать Int в HEX, HEX в строку и в байт? Общая проблема конвертации

Поскольку Cpp не является моим основным языком, я изо всех сил пытаюсь найти лучший способ преобразования между типами для моих нужд. Итак, моя отправная точка

struct can_frame {
    canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
    __u8    can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
    __u8    data[CAN_MAX_DLEN] __attribute__((aligned(8)));
};

Итак, сначала мне нужно было отправить его в Serial в виде шестнадцатеричной строки, поэтому решение, которое я нашел и использовал, было

String frame = "CAN:";
char dataString[1] = {0};
sprintf(dataString, "%03X", can1Msg.can_id);
frame += dataString;
for (int i = 0; i < can1Msg.can_dlc; i++) {  // вывести данные
  char dataString[1] = {0};
  sprintf(dataString, "%02X", can1Msg.data[i]);
  frame += " " + String(dataString);
}

Выглядит не очень элегантно, потому что работает.

Но затем мне нужно было проверить идентификатор и определенные байты Итак, я сохранил все String ins String bytes[8] Итак, теперь я мог бы что-то вроде

if (id == "2A0" && bytes[0] == "A0") {

И это было почти закончено, но потом я понял, что мне нужно сделать некоторую проверку целого числа, которое сохраняется на 3 байта. Например, byte[2] + byte[3] + byte[4], что-то вроде 0020A0, которое будет 8352 как Int

Но преобразование вещей вызвало все проблемы, такие как String to const char* и т. д. Я хотел преобразовать __u8 в массив байтов, чтобы я мог выполнять проверки и преобразования и в конечном итоге преобразовать его в строку, но мне это не удалось. Может ли кто-нибудь предложить лучший подход для этого?

, 👍-2

Обсуждение

Обратите внимание, что вы переполняете массивы dataString из 1 ячейки. Вероятно, это портит часть вашей памяти., @Edgar Bonet


1 ответ


Лучший ответ:

1

Основная проблема, с которой вы столкнулись, — непонимание того, что такое "шестнадцатеричный", "байтовый" и т. п.

Вы пытаетесь работать с четырьмя типами данных (целое, шестнадцатеричное, строковое и байтовое), хотя на самом деле существует только два типа: строковый и двоичный. Все остальное — это просто представление, которое мы, люди, используем для облегчения понимания двоичных данных.

У вас есть "источник" тип (can1Msg.data), который одновременно является двоичным, целым, шестнадцатеричным и байтовым. Единственное, чем он не является, это String, и вы создаете его вручную с помощью вызовов sprintf.

Чтобы сравнить третью "шестнадцатеричную пару" значение в ваших данных, вы просто:

if (can1Msg.data[2] == 0x42) { ...

То есть сравните 8-битное двоичное значение, хранящееся в фрагменте массива 2 (массивы отсчитываются от 0, поэтому 2 – третья запись), с двоичным значением, представленным шестнадцатеричным представлением 42. То же самое можно сделать с помощью:

if (can1Msg.data[2] == 66) { ...

66 — это десятичный (с основанием 10) эквивалент 0x42. Вы также можете использовать двоичный или восьмеричный формат. Эти два также точно такие же:

if (can1Msg.data[2] == 0102) { ... // восьмеричное число
if (can1Msg.data[2] == 0b01000010) { ... // двоичный

Если вам нужно проверить группы байтов, например, если у вас есть два байта, которые образуют 16-битное целое число, вы просто объединяете эти два байта в целое число, соблюдая правильный порядок байтов значений. Например, если у вас есть 16-битное целое число, которое хранится как can1Msg.data[7] и can1Msg.data[8] в формате big endian можно использовать:

uint16_t val = (can1Msg.data[7] << 8) | can1Msg.data[8];

Затем просто сравните числовое (двоичное) целое значение по желанию. Все, что делает эта строка, это берет первое 8-битное значение и "shift" это 8 бит влево, чтобы сделать его 16-битным значением с младшими 8 битами, установленными на 0, затем наложить второе значение на эти младшие 8 нулей, чтобы сделать его одним 16-битным значением.

,

Большое спасибо. Моя ошибка заключалась в том, что я почему-то предположил, что то, что у меня есть в данных, не является байтом и в голове засело, что мне нужно преобразовать это в байт., @uneasy