Введение
Вопрос неясен, поэтому я расскажу о трех очевидных возможностях.
Заголовок фиксированной длины, за которым следует полезная нагрузка переменной длины
Типичный способ определения пакет для сетевой службы или службы обмена сообщениями должен иметь заголовок фиксированной длины, за которым следует полезная нагрузка переменной длины. В современном C полезная нагрузка переменной длины может быть определена с использованием гибкого элемента массива, который является массивом без измерения в конце структуры:
typedef struct
{
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
uint8_t payload[];
} mb32_packet_t;
Выделена память для такой структуры используйте базовый размер, предоставляемый sizeof
, плюс дополнительную память для полезной нагрузки:
mb32_packet_t *MyPacket = malloc(sizeof *MyPacket + PayloadLength);
Когда вы передаете такой объект подпрограмме, для которой в качестве аргумента требуется char *
или uint8_t *
или аналогичный тип Вы можете просто преобразовать указатель:
SendMyMessage(…, (uint8_t *) MyPacket,…);
Это приведение, (uint8_t *) MyPacket
, предоставляет указатель на первый байт пакета, запрошенного в вопросе. Нет необходимости вклинивать другого члена в структуру или слой в объединении или другом объявлении.
До введения членов гибкого массива в C 1999 люди использовали один из двух обходных путей для создания структур. с переменным количеством данных. Во-первых, они могут просто определить массив элементов с одним элементом и соответствующим образом скорректировать вычисления пространства:
typedef struct
{
…
unsigned char payload[1];
} mb32_packet_t;
mb32_packet_t *MyPacket = malloc(sizeof *MyPacket + PayloadLength - 1);
Технически это нарушает стандарт C, поскольку структура содержит массив только из одного элемента, хотя для этого было выделено больше места. Однако компиляторы не были так агрессивны в своем анализе семантики программ и их оптимизации, как сейчас, поэтому в целом это работало. Таким образом, вы все еще можете видеть старый код, использующий этот метод.
Два, G CC имел собственную предстандартную реализацию гибких элементов массива, просто используя нулевое измерение массива вместо пропуска измерения:
typedef struct
{
…
unsigned char payload[0];
} mb32_packet_t;
Опять же, вы можете увидеть старый код, использующий это, но новый код должен использовать стандартный элемент гибкого массива.
Заголовок фиксированной длины с указателем на полезную нагрузку переменной длины
Форма полезной нагрузки после заголовка, показанная выше, является формой пакета, который я больше всего ожидал бы в пакете обмена сообщениями, потому что он соответствует тому, что аппаратное обеспечение должно поставить «на провод» при отправке байтов по сети: он записывает байты заголовка сопровождаемый байтами данных. Поэтому удобно расположить их таким образом в памяти.
Однако ваш код показывает другой вариант: данные не находятся в пакете, но на них указывает указатель в пакете с uint8_t *payload;
. Я подозреваю, что это ошибка, что служба сети или обмена сообщениями действительно хочет иметь элемент гибкого массива, но вы показываете его, за которым следует другой член, uint16_t checksum
. Член гибкого массива должен быть последним членом в структуре, поэтому тот факт, что после полезной нагрузки есть другой член, предполагает, что это определение с указателем может быть правильным для службы обмена сообщениями, с которой вы работаете.
Однако, в этом случае невозможно получить указатель на полный объект пакета, потому что объект состоит из двух частей. Один содержит заголовок, а другой, в некотором несвязанном месте в памяти, содержит данные.
Как указано выше, вы можете создать указатель uint8_t *
на начало пакета с помощью (uint8_t) MyPacket
. Если система обмена сообщениями знает о указателе в структуре, это должно работать. Если вы ошиблись, какой должна быть структура пакета, он потерпит неудачу.
Заголовок фиксированной длины, за которым следует пространство полезной нагрузки фиксированной длины
Код в другом месте переполнения стека показывает struct mb32_packet_t
с фиксированным объемом пространства для полезной нагрузки:
typedef struct mb32_packet_t {
uint8_t compid;
uint8_t servid;
uint8_t payload[248];
uint8_t checksum;
} __attribute__((packed)) mb32_packet_s;
В этой форме пакет всегда имеет фиксированный размер, хотя объем пространства используется для полезной нагрузки может варьироваться. Опять же, вы получите uint8_t *
указатель на пакет при помощи приведения. Для этого не нужен специальный член.