Следует ли использовать макросы вместо членов гибкого массива? - PullRequest
0 голосов
/ 14 декабря 2018

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

Я хотел бы создать структуру для 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 ]

0 голосов
/ 14 декабря 2018

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

0 голосов
/ 14 декабря 2018

Размер 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 с измененной полезной нагрузкой.

...