Поля в структуре пропускают байты - PullRequest
3 голосов
/ 18 августа 2010

У меня есть структура, которую я написал, которая должна представлять весь пакет UDP, с заголовком ethernet и всем. Вот оно:

#pragma pack(1)
struct UDPPacket {
    // an array to hold the destination mac address of the packet
    unsigned char dstmac[6];

    // an array to hold the source mac address of the packet
    unsigned char srcmac[6];

    // two bytes to hold the packet type, this is almost always IP (08 00)
    WORD ethtype;

    // each of the subfields of this take up 4 bits. ver, the first half,
    // is the ip version, which should usually be 4 for ipv4, and the second
    // is the length of the header divided by 4, which is almost always 5
    struct {
        unsigned ver : 4;
        unsigned len : 4;
    } verlen;

    // this isn't used in ipv4 and is 0
    BYTE tos;

    // the total length of the header + data
    WORD iplen;

    // the id of this datagram for reassembling fragmented packets
    WORD id;

    // the first subfield occupies 3 bits and is the flags of this packet, which is usually 0
    // the second subfield is the fragmentation offset for large datagrams that have been split up for sending, usually 0
    struct {
        unsigned flags : 3;
        unsigned fragmentation : 13;
    } flagfrag;

    // time to live; usually 35 or 128
    BYTE ttl;

    // the protocol with which this packet is being transported
    // 1 = ICMP, 2 = IGMP, 6 = TCP, 17 = UDP
    BYTE protocol;

    // the ip checksum of this packet
    WORD ipchecksum;

    // the source ip of this packet
    DWORD src;

    // the destination ip of this packet
    DWORD dest;
    // the port from which this packet is coming
    WORD srcport;

    // the port this packet is headed to
    WORD destport;

    // the length of the udp header + data, not including the ip header
    // so it's usually basically iplen - 20
    WORD udplen;

    // the udp checksum of this packet
    WORD udpchecksum;

    // a char pointer to the data of the packet
    unsigned char data[10000];
};
#pragma pack()

Конечно, это представление реального UDP-пакета, байты должны иметь одинаковое смещение, как в пакете, и указатели на этот тип структуры будут приведены к unsigned char* с для отправки .
Моя проблема в том, что когда я пытаюсь назначить что-либо после UDPPacket.verlen, он пропускает около 5 байтов и начинает там. Например, когда я назначаю поле iplen вместо установки байтов со смещением 16 и 17, оно присваивает им что-то вроде 23 и 24 (я не могу сказать точно, потому что у меня нет моей программы, доступной здесь, на мой телефон).
Есть ли очевидная причина, по которой я скучаю, или я просто сделал что-то не так?

Ответы [ 6 ]

2 голосов
/ 18 августа 2010

Ваш #pragmas выглядит правильно. Битовые поля не «автоматически упаковываются» в наименьший тип, который соответствует количеству битов, указанному явно. Я подозреваю, что verlen принимает ваш тип unsigned и предполагает, что это bitfiend размера unsigned int, который звучит как 32 бит в вашем компиляторе. Попробуйте вместо этого сделать поля verlen "unsigned char".

Подробнее здесь. Возможность указать «unsigned char» здесь является расширением MSFT (до ANSI C), но должна работать: http://msdn.microsoft.com/en-us/library/yszfawxh(VS.80).aspx

N.B. То же самое относится и к flagfrag, что должно быть "unsigned short".

1 голос
/ 18 августа 2010

Ваша директива #pragma pack верна, но я думаю, что базовый тип ваших полей (verlen и flagfrag) int вместо ожидаемых char и short.

1 голос
/ 18 августа 2010

Стандарт не требует, чтобы компилятор упаковывал битовые поля в один модуль хранения (int, char, что угодно).Так что даже с прагмой я бы ожидал, что эти 2 битовых поля будут занимать 2 символа или целые.У меня нет документации для этого компилятора - это говорит о том, как прагма влияет на битовые поля?

0 голосов
/ 18 августа 2010

unsigned здесь эквивалентно unsigned int, что составляет 4 байта.Так что iplen должно быть по смещению 23, что звучит так, как оно есть.

0 голосов
/ 18 августа 2010

Возможно, использование макроса offsetof поможет вам.

0 голосов
/ 18 августа 2010

Вы должны проверить настройки отступов и выравнивания вашего компилятора.

...