Следует ли использовать макросы вместо членов гибкого массива?

Давайте предположим следующее:

Я хотел бы создать структуру для пакетов 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 к измененной полезной нагрузке все время.

Выделите память для полезной нагрузки и контрольной суммы. Используйте указатель для доступа к контрольной сумме. Легко и эффективно

Другие вопросы по тегам