Следует ли использовать макросы вместо членов гибкого массива?
Давайте предположим следующее:
Я хотел бы создать структуру для пакетов UDP. Каждый кадр обычно состоит из заголовка Ethernet, заголовка IP, заголовка UDP и необязательной полезной нагрузки, за которой следует, наконец, FCS (последовательность контрольной суммы кадра).
Длина полезной нагрузки неизвестна / гибкая. Это означает, что при создании структуры полезная нагрузка должна быть последним ее членом ( гибкий элемент массива). Следовательно, нет места для ФТС.
Поэтому я подумал о том, какие возможности останутся.
Я придумал следующий кусок кода:
#define UDP_PKT(name, payload_length) struct __attribute((__packed__)) \
{ \
struct ether_header eth; \
struct ip iph; \
struct udphdr udph; \
unsigned char payload[payload_length]; \
u_int32_t fcs; \
} name;
Как это не разрешено:
struct __attribute__((__packed__)) udp_packet
{
struct ether_header eth;
struct ip iph;
struct udphdr udph;
unsigned char payload[]; // fam, must always be the last member
u_int32_t fcs;
};
Мой вопрос: это единственная возможность, я должен включить FCS в структуру, не имея фиксированного размера массива (полезной нагрузки)?
Если так, то это хорошее решение? Это считается хорошей практикой?
2 ответа
Размер struct
с гибким элементом массива определяется во время выполнения, поэтому ваш первый подход также не будет работать. Решение состоит в том, чтобы поместить FCS в конец буфера, когда вы будете готовы к сериализации struct
для провода:
struct __attribute__((__packed__)) udp_packet {
struct ether_header eth;
struct ip iph;
struct udphdr udph;
u_int32_t fcs;
unsigned char payload[]; // Move fcs up
};
void serialize_udp_packet(const udp_packet* p) {
// Compute buffer size, and allocate the buffer
// Place the header into the buffer
// Copy the payload into the buffer
// Place FCS into the buffer at the end
}
Вы могли бы даже исключить fcs
от udp_packet
и вычислять его только при сериализации struct
, Одним из преимуществ этого подхода является то, что вы можете свободно изменять полезную нагрузку, не синхронизируя FCS
к измененной полезной нагрузке все время.
Выделите память для полезной нагрузки и контрольной суммы. Используйте указатель для доступа к контрольной сумме. Легко и эффективно