Форма 16-битных слов из структуры

0

Поэтому я работаю над созданием эхо-запроса ICMPv4 и решил запустить мою собственную структуру для хранения пакета. Чтобы сделать идентификацию пакета легко идентифицировать в wirehark, я решил поместить abcde в поле данных.

struct icmpPacket{
    u_int8_t icmp_type:8, icmp_code:8;
    u_int16_t icmp_checksum:16, icmp_id:16, icmp_seqnum:16;
    char icmp_data[6]; //cheat a little bit, set the field just large enough to store "abcde";
    } __attribute__((aligned (16))) icmppckt; // icmp has an 8 byte header + 6 bytes of data

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

  • 0
    msgstr "как заставить компилятор читать структуру как последовательность 16-битных слов" . Что вы имеете в виду? Вы можете использовать union но я не знаю, имеете ли вы это в виду.
  • 0
    Я хотел бы передать структуру в функцию, которая принимает u_int16_t * в качестве параметра
Показать ещё 6 комментариев
Теги:
struct

2 ответа

1

Стандартный способ для этого - через memcpy:

icmpPacket packet = { /* ... */ };
uint16_t buf[sizeof(icmpPacket) / sizeof(uint16_t)];
memcpy(buf, &packet, sizeof(icmpPacket));
/* Now use buf */

Современные компиляторы достаточно умны, чтобы оптимизировать их соответствующим образом, фактически не выполняя вызов функции. См. Примеры с clang и g++).

Общее расширение компилятора позволяет использовать союзы, хотя это неопределенное поведение в стандарте C++:

union packet_view{
    icmpPacket packet;
    uint16_t buf[sizeof(icmpPacket) / sizeof(uint16_t)];
};
icmpPacket packet = { /* ... */ };
packet_view view;
view.packet = packet;
/* Now read from view.buf. This is technically UB in C++ but most compilers define it. */

Использование reinterpret_cast<uint16_t*>(&packet) или его эквивалент C нарушит строгие правила псевдонимов и приведет к неопределенному поведению. §3.10 [basic.lval]/p10 стандарта C++:

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

  • динамический тип объекта,
  • cv-квалифицированная версия динамического типа объекта,
  • тип, аналогичный (как определено в 4.4) для динамического типа объекта,
  • тип, который является подписанным или неподписанным типом, соответствующим динамическому типу объекта,
  • тип, который является подписанным или неподписанным типом, соответствующим версии с динамическим типом объекта cv,
  • совокупный или тип объединения, который включает один из вышеупомянутых типов среди его элементов или нестатических членов данных (включая рекурсивно элемент или нестатический элемент данных субагрегата или содержащегося объединения),
  • тип, который является (возможно, cv-квалифицированным) типом базового класса динамического типа объекта,
  • char или unsigned char type.

Аналогично, в §6.5/p7 из C11 говорится:

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

  • тип, совместимый с эффективным типом объекта,
  • квалифицированную версию типа, совместимую с эффективным типом объекта,
  • тип, который является подписанным или неподписанным типом, соответствующим эффективному типу объекта,
  • тип, который является подписанным или неподписанным типом, соответствующим квалифицированной версии эффективного типа объекта,
  • совокупный или союзный тип, который включает один из вышеупомянутых типов среди его членов (включая рекурсивно, член субагрегата или объединенного объединения) или
  • тип символа.
  • 0
    Приведение -1 не является неопределенным поведением: определяется структура памяти структуры, а также структура массива (в противном случае даже memcpy не будет работать). Это запрещено оптимизацией компилятора (которая может быть отключена локально). tp для профсоюзов допускается в некоторых случаях (см. другой комментарий).
  • 0
    @AdrianoRepetti Нет, строгий псевдоним обязателен стандартом.
Показать ещё 14 комментариев
0

вы можете использовать 16-битные указатели для этого

  • но вам нужно добавить выравнивание в 1 байт элементов структуры !!!
  • в C++ вы можете сделать это следующим образом:

    #pragma pack(1)
    struct icmpPacket
        {
        u_int8_t icmp_type:8, icmp_code:8;
        u_int16_t icmp_checksum:16, icmp_id:16, icmp_seqnum:16;
        char icmp_data[6]; //cheat a little bit, set the field just large enough to store "abcde";
        } icmppckt; // icmp has an 8 byte header + 6 bytes of data
    WORD *picmppckt16=(WORD*)((void*)&icmppckt);
    #pragma pack()
    
  • измените WORD на 16-битный тип данных, который ваш компилятор знает...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню