我有两个完全相同的代码:
struct sniff_ip {
u_char ip_vhl; /* version << 4 | header length >> 2 */
...
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
和
struct sniff_ip {
uint8_t ip_hl:4;
uint8_t ip_ver:4;
...
};
前者是来自http://www.tcpdump.org/pcap.html
的代码后者是我的
这两个代码的IP版本和IP头长度改变位置,但输出是相同的,为什么?
我的意思是#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
查看后四位,当声明uint8_t ip_hl:4
捕获前四位时...
答案 0 :(得分:2)
不要使用位域来实现协议!确切位置取决于ABI并且取决于平台/编译器。
你的假设
当uint8_t ip_hl:4被声明为捕获前四位时
是错误的。对您的编译器有效,但不能一般化。您必须非常仔细地阅读编译器/ ABI文档,以找出真正放置位的位置。
如何定义位域的示例可以在ARM EABI规范http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf&#34; 7.1.7位域&#34;中找到。但对于x86或mips ABI来说,这可能完全不同
编辑:
Bitfields可以节省空间(例如unsigned int flag:1
与bool flag
)[这种假设可能不成立,因为检查需要更多(和更慢)的机器代码]并使代码更容易阅读(例如if (a->flags & (1 << 0))
与if (a->some_flag)
)。但你永远不能依赖确切的职位。