跳过字节的结构中的字段

时间:2010-08-18 14:38:45

标签: c++ visual-studio-2008 struct field byte

我有一个我编写的结构,它应该代表整个UDP数据包,带有以太网头和所有。这是:

#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 个答案:

答案 0 :(得分:2)

你的#pragmas看起来正确。位域不会“自动打包”到符合显式指定位数的最小类型。我怀疑verlen正在使你的给定类型“无符号”,并假设它是一个大小为unsigned int的bitfiend,在你的编译器中听起来像是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 :(得分:1)

该标准不要求编译器将位字段打包到单个存储单元(int,char,等等)。因此即使使用pragma,我也希望这2个字段占用2个字符或整数。我没有该编译器的文档 - 它是否说pragma如何影响位域?

答案 2 :(得分:1)

您的#pragma pack指令是正确的,但我认为您的bifield(verlenflagfrag)的基础类型是int而不是char和你期待short

答案 3 :(得分:0)

您必须检查编译器的填充和对齐设置。

答案 4 :(得分:0)

也许使用offsetof macro会对您有帮助。

答案 5 :(得分:0)

unsigned在此等效于unsigned int,即4个字节。所以iplen应该是偏移23,听起来就像是。