Преобразование беззнакового целого числа в указатель const char

Я знаю, что это простой базовый материал языка Си, но я не могу полностью понять его или найти решение при поиске и чтении.

У меня есть метод который я хочу вызвать из библиотеки которому нужен указатель const char

someclass::send(const char *data)

А значение, которое я хочу отправить, на самом деле является целым числом без знака:

enum messageTypeEnum
{
  REGISTER_CLIENT = 0x04,
  CLIENT_REGISTERED,
  UPDATE_CREDENTIALS,
  ADD_BRICK,
  GAME_FRAME,
  ERROR
};

enum clientTypeEnum
{
  GAMEBOARD = 0x01,
  BRICK_CONTROLLER,
  PLAYER_CONTROLLER,
  TOUCH_CONTROLLER
};

uint16_t message = GAMEBOARD;
message <<= 8;
message += REGISTER_CLIENT;

Поэтому я хочу преобразовать его, но никак не могу понять.

Я знаю, принципиально чар указатель-это просто указатель на адрес памяти, что и в C строки заканчиваются нулем, поэтому я должен быть в состоянии создать указатель, добавить перечисление базового байтов в массив указателей, а затем добавить 0 в конце, чтобы завершить это, но я не знаю, как бы я сделать это ровно.

Я попробовал сделать это через кастинг:

const char *data = (char *)&message;

Итак, вот что я хочу сказать (если я правильно об этом думаю):

  • &message возьмите адрес памяти сообщения, наш uint16
  • `(char *) интерпретирует его как указатель на символьную строку
  • const char * сохраните этот адрес в этом указателе const

Даже печатая это, я чувствую, что неправильно понимаю некоторые детали.

Это компилируется, но он падает мой esp32, и я уверен, что это потому, что у меня нет нулевого терминатора в конце, но я не уверен, как его добавить (я пытался добавить его через индекс массива, но это не удалось).

Как правильно это сделать (я уверен, что есть способ без кастинга, который, вероятно, проще)?

Обновление

Более подробно re: PMF и комментарии Эдгара.

Я определенно хочу отправить двоичные числа, стоящие за перечислениями, вверх. Я создаю интерактивный проект на основе websocket, в котором клиенты websocket "controller" могут управлять взаимодействиями на "игровых платах". У Websockets нет концепции дифференциации между типами клиентов (я знаю socket.io делает, но я хочу написать все это с обычными websockets), поэтому я построил систему регистрации в сервер, который смотрит на первые два байта буфера массива или blob-сообщения, чтобы определить тип клиента и сообщения (это кажется слишком сложным, но я строю это, чтобы дать разговор о двоичных операциях, и я делаю это, чтобы дать функциональные примеры анализа данных).

Так что да, все это говорит о том, что я определенно хочу отправить базовые числовые значения из перечислений.

Библиотека, которую я использую, - это ArduinoWebsockets, и у них есть клиентский метод sendBinary, который действительно имеет сигнатуру, подобную Serial.write:

sendBinary signature

Хотя, когда я попробовал это сделать с ненулевой завершенной c-строкой, мой esp32 разбился. Тем не менее, я копался в коде, так что, возможно, причиной сбоя было что-то другое.

Когда я следую вызовам метода вниз, библиотека в конечном счете использует std::string для извлечения данных из переданной в c-строке и принимает длину (это означает, что она не должна заканчиваться null(?)):

Так, может быть, я могу использовать приведение, чтобы превратить мой двухбайтовый номер в строку c и передать в длину 16?

, 👍1

Обсуждение

Вы уверены, что хотите отправить значение _binary_ 0x01? Я думаю, что это скорее ваша библиотека, которая падает из-за этого, а не вызывающая функция. Хотя это неверно (как вы правильно предполагаете), "сообщение" на самом деле является двоичным 0x01 0x00 (esp32 является небольшим endian), и поэтому у него есть конечный 0, если значение меньше 256., @PMF

Serial.write() имеет перегрузку write(const uint8_t *buffer, size_t size), которая позволяет выводить произвольный массив байтов и не требует нулевого терминатора (0-допустимое значение для вывода). Я видел такую перегрузку в других библиотеках. Ваш "someclass" может предложить нечто подобное для отправки двоичных данных. Если это не так, то он, вероятно, не предназначен для отправки чего-либо, кроме текста, и в этом случае вам придется сериализовать свои данные в виде текста., @Edgar Bonet

Я действительно хочу отправить двоичные значения вверх, потому что я анализирую сообщения на сервере как 8-битные массивы буферов или больших двоичных объектов, и у меня есть те же перечисления на сервере и других клиентах, чтобы координировать сообщение и идентификацию клиента., @Chris Schmitz

Ah @EdgarBonet да в библиотеке есть метод sendBinary, который принимает строку c и длину, хотя я столкнулся с проблемами при попытке использовать его. Тем не менее, я, вероятно, понимаю это неправильно. Я обновлю свой вопрос более подробно., @Chris Schmitz


1 ответ


1

ИСПРАВЛЕННЫЙ ОТВЕТ

Я покопался в своем коде после комментария Эдгара и вычислил некоторые необходимые корректировки. Мое первоначальное решение было в основном правильным, но были некоторые неточности, которые я хочу исправить, чтобы в будущем не обманывать никого другого, кто может найти этот ответ полезным.


Так что я немного переусердствовал. Я все еще не знаю, что это лучший способ справиться с этим, но он работает на стороне клиента.

Таким образом, c-строки-это просто массивы 8-битных значений с нулевым терминатором в конце.

Я хочу закончить свои значения перечисления, и мои перечисления определяются с помощью байтовых баз перечисления:

enum messageTypeEnum
{
  REGISTER_CLIENT = 0x04,
  CLIENT_REGISTERED,
  UPDATE_CREDENTIALS,
  ADD_BRICK,
  GAME_FRAME,
  ERROR
};

enum clientTypeEnum
{
  GAMEBOARD = 0x01,
  BRICK_CONTROLLER,
  PLAYER_CONTROLLER,
  TOUCH_CONTROLLER
};

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

ПРИМЕЧАНИЕ: это исходная сборка, которая была неправильной. Я поставил нулевой терминатор в начале буфера, думая: "О, это маленький эндианец, поэтому терминатор должен быть в начале". Классическая сонная ошибка мозга :|

void registerAsAGameBoard() { char buffer[3] = {0, GAMEBOARD, REGISTER_CLIENT};

client.sendBinary((const char *)буфер, 3); }

void registerAsAGameBoard()
{
  char data[3] = {GAMEBOARD, REGISTER_CLIENT, 0};

  const char *buffer = data; 
  size_t size = strlen(buffer);

  client.sendBinary(buffer, size);
}

Теперь, когда я вызываю sendBinary с моим байтовым массивом и длиной буфера, мой esp32 не падает (ура!), И сервер получает буфер правильно!!

success!

Мне нужно сделать пару корректировок на стороне клиента и/или сервера, чтобы учесть тот факт, что ESP32 является little endian, и сервер уже закодирован для получения полезных нагрузок в big endian, но это не должно быть слишком большим подъемом.

,

Обратите внимание, что в char buffer[3] = {0, GAMEBOARD, REGISTER_CLIENT}; байт 0 не является “нулевым терминатором”: это первый байт буфера, тогда как “терминатор” по определению находится в конце., @Edgar Bonet

@EdgarBonet, вы правы, и я рад, что вы указали на это. Я не понимал, почему именно эта установка предотвратила аварию. Я покопался дальше и обнаружил, что когда поставил терминатор null в правильное место, контроллер все равно разбился, но он разбился в другой части кода, где мы обрабатываем разные сообщения с сервера. Я прокомментировал эту часть, и контроллер перестал сбоить в обоих местах. Затем я обновил код с правильным нулевым терминатором и все уладил. Я обновляю свой ответ., @Chris Schmitz