2010-08-18 46 views
3

我有一个结构,我已经写了,它应该代表整个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* s发送。
我的问题是,当我尝试在UDPPacket.verlen之后分配任何内容时,它会跳过大约5个字节并从那里开始。例如,当我指定iplen字段时,不是将字节设置为偏移量16和17,而是将它们指定为类似于23和24的字符(我不能完全说明,因为我的手机中没有可用的程序)。
有没有一个明显的原因,我错过了,或者我只是做错了什么?

+0

顺便说一下,我在x64 Windows 7上使用Visual Studio 2008,但是为x86编译。 – Hock 2010-08-18 14:39:30

回答

2

#pragmas看的权利。位字段不会“自动打包”为符合明确指定位数的最小类型。我怀疑verlen将你的给定类型“无符号”,并假设它是一个无符号整数大小的位,这听起来像你的编译器中的32位。请尝试将verlen的字段改为“无符号字符”。

更多这里。能够指定“无符号的字符”这里是一个MSFT扩展(以ANSI C),但应该工作:http://msdn.microsoft.com/en-us/library/yszfawxh(VS.80).aspx

注: flagfrag同样适用于“无符号短”。

+0

之前,我认为它不是什么类型,因为你只是指定它应该占用的位数,但现在我认为你指定了一个占用一定数量字节的类型(并且因此位),那么你可以在结构中有不同的位域,只要它们加起来就是你之前指定的类型。那是对的吗? – Hock 2010-08-18 15:13:07

+0

我相信在C++中这不是一个扩展,而是来自标准的一个要求。我将不得不再次仔细地阅读语法,如果我为此收集时间,我今晚可能会尝试。 – 2010-08-18 15:20:41

+0

是的,基本上编译器只关心你用作位域的底层类型;命名单个位的能力仅仅是一个语法上的便利 - 它不会引入新的“位”类型或类似的东西。如果这就是你要求的,那么你不可能(尽管你应该尝试它或者阅读文档),你可以在结构中的位域中间拥有完整的较小类型。 – 2010-08-18 15:20:47

0

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

1

该标准不要求编译器包装位字段成一个单一的存储单元(INT,炭,等等)。所以即使使用编译指示,我也希望这两个位字段占用2个字符或整数。我没有该编译器的文档 - 它是否说该编译指示如何影响位域?

1

#pragma pack指令是正确的,但我认为基本类型的bifields(verlenflagfrag)是int,而不是charshort您所期望。

0

unsigned相当于这里unsigned int,这是4个字节。所以iplen应该在偏移量23,这听起来像是。