Чтение битов из указателя const char

В последнее время я немного путаюсь в указателях const char.

Я получаю сообщение от сервера, которое приходит либо в виде строки в стиле c, либо в виде строки стандартной библиотеки, либо в виде WString:

return types

underlying types

Я отправляю вниз буфер из 32-битных значений с моего сервера, которые не являются текстом ascii или utf, это просто битовые значения, которые я хочу разобрать и прочитать на стороне esp32:

example data from the server

Я подумал: "О, я просто замаскирую битовые значения 32 бита за раз и сдвину данные вправо, чтобы получить сообщение (в обратном порядке, но все же я могу работать с этим). Проблема, с которой я столкнулся, заключается в том, что я могу сдвигать числа, но не строки или байтовые массивы.

Я написал функцию, позволяющую мне захватить кусок строки 32 бита за раз и преобразовать его в число, используя смещение:

uint_fast32_t get32BitInt(const char *data, int offset = 0)
{

  uint32_t payload = 0;
  for (uint8_t i = 0; i < 8; i++)
  {
    payload <<= 0;
    payload += data[i + offset];
  }
  return payload;
}

Но когда я пытаюсь захватить первую пару 32-битных фрагментов, данные не такие, как я ожидал:

void handleGameFrame(const char *data, uint32_t length)
{

  uint8_t phaseAndColission = get32BitInt(data, 32);
  uint8_t player = getByte(data, 32 * 2);

  Serial.print("data: ");
  Serial.println(data);
  Serial.print("phaseAndColission: ");
  Serial.println(phaseAndColission, DEC);
  Serial.print("player: ");
  Serial.println(player, DEC);

}

урожайность:

Я знаю, что Serial.println(data); не собирается ничего выводить b/c, это c-строка непечатаемых значений, но другой захват фрагмента не дает мне такого же вывода с моего сервера. Трудно проверить все, не имея возможности увидеть все биты в общем указателе данных, и я думаю, что связал себя в (другом) узле.

Есть ли хороший способ разобрать 32-битные значения из константной c-строки?

, 👍0

Обсуждение

"это просто битовые значения". Вы имеете в виду, что они просто "uint32_t", на которые указывают с помощью " const char *` ?, @timemage

О, я просто имею в виду, что данные (const char *) содержат биты, которые не могут быть Serial.println-ed, потому что даже в 8-битной форме они не являются допустимыми символами ascii/utf, поэтому ничто не попадает на монитор., @Chris Schmitz

но да, данные-это c-строка байтов, и я знаю, что хочу интерпретировать ее как 32-битные целые числа, я просто не могу понять, как это сделать., @Chris Schmitz

Ну, "с-строка" в основном означает ноль или более не- "\0", за которыми следует "\0". Если какое-либо из ваших чисел случайно имеет нулевой байт в них, это завершит "строку" до конца ваших фактических данных. Например, 0xAA00BB. На самом деле это вовсе не струна. С точки зрения того, как вы получаете из него данные, если они правильно выровнены для uint32_t, вы можете просто const uint32_t *ui32p = reinterpret_cast<const uint32_t *>(mycharptr); Если он не выровнен, вы сделаете что-то вроде "memcpy" в массив или отдельные элементы в одну переменную "uint32_t". Здесь нет ничего действительно "Arduino"., @timemage

может потребоваться шестнадцатеричное кодирование значений, чтобы передать их., @dandavis

это похоже на проблему X->Y. "Я получаю сообщение от сервера, которое приходит либо в виде строки в стиле c, либо в виде строки стандартной библиотеки, либо в виде WString" почему?, @Juraj

@Juraj это форматы сообщений, которые дает мне библиотека, которую я использую. Там нет опции только для буфера байтов. Я бы подумал, что c-string является эквивалентом буфера, но есть проблема с терминатором null., @Chris Schmitz


1 ответ


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

1

Вы написали:

Я написал функцию позволяющую мне захватывать кусок строки по 32 бита за раз и преобразовывать его в число используя смещение

Эта функция почти правильна. Попробуйте это:

uint_fast32_t get32BitInt(const char *data, int offset = 0)
{

  uint32_t payload = 0;
  for (uint8_t i = 0; i < 4; i++)
  {
    payload <<= 8;
    payload |= data[i + offset];
  }
  return payload;
}

По сравнению с вашей версией различия заключаются в следующем:

  • Он считывает 4 байта вместо 8, так как 32 бита-это четыре байта.

  • Для каждого считываемого байта он сдвигает полезную нагрузку на 8 бит (то есть на один байт) вместо нуля. Сдвиг на ноль не имеет никакого эффекта.

  • Он использует |= вместо +=: просто микрооптимизация ради 8-битных микроконтроллеров. Это не должно иметь большого значения, если речь идет о 32-битном микропроцессоре.

,

О боже мой. Я не могу поверить, что пропустил этот сдвиг на ноль :facepalm: Я знаю, что условная проверка for loops также ошибочна, но я не могу поверить, что пропустил ошибку сдвига. Спасибо, что указали на них, а также на побитовую оптимизацию или оптимизацию. Я ценю, что вы нашли время, чтобы исправить эту функцию :луки:, @Chris Schmitz