位域的字节序是由实现定义的。是否有一种方法可以在编译时通过某些宏或其他编译器标志来检查gcc的位域字节序是什么?
换句话说,给定以下内容:
struct X {
uint32_t a : 8;
uint32_t b : 24;
};
在编译时,有没有一种方法可以让我知道a
是不是X
的第一个或最后一个字节?
位域的字节序是由实现定义的。是否有一种方法可以在编译时通过某些宏或其他编译器标志来检查gcc的位域字节序是什么?
换句话说,给定以下内容:
struct X {
uint32_t a : 8;
uint32_t b : 24;
};
在编译时,有没有一种方法可以让我知道a
是不是X
的第一个或最后一个字节?
__BYTE_ORDER
宏,以查看它是__LITTLE_ENDIAN
还是__BIG_ENDIAN
。虽然这不是权威性的,但在实践中应该可以工作。struct iphdr
中,这是用于IP头的结构体。第一个字节包含两个4位字段,这些字段被实现为位域,因此顺序很重要。struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
u_int8_t tos;
u_int16_t tot_len;
u_int16_t id;
u_int16_t frag_off;
u_int8_t ttl;
u_int8_t protocol;
u_int16_t check;
u_int32_t saddr;
u_int32_t daddr;
/*The options start here. */
};
位域始终分配给第一个可用位,可能受其他因素(例如对齐)的限制。这意味着它们从小端的低位开始,从大端的高位开始。这是做事情的“正确”方式。编译器以不同的方式执行此操作非常不寻常。
- user9041001netinet/ip.h
副本说:“此文件是GNU C库的一部分”,因此它与GCC紧密绑定。另一方面,您的头文件应该在假定使用__BYTE_ORDER
来控制位域排序是安全的之前检查#ifdef __GNUC__
。#error
也是一个逃避责任的行为 - 如果__BYTE_ORDER == __PDP_ENDIAN
会怎样呢? - kbro有趣的是,当位域是8位的倍数时,体系结构的字节序似乎并不重要。
请参见此处 [godbolt.org]
我在这个godbolt示例中选择了arm架构,因为它支持大端和小端,并且很容易比较差异。
请注意,无论体系结构是大端还是小端,在两种情况下,8位字段都位于结构的开头。
我测试了所有可以为is_8bit_tag_at_start函数生成可读汇编代码的godbolt编译器,它们似乎都返回true。
htonl
将网络字节序转换为主机字节序,然后再使用ntohl
将主机字节序转换为网络字节序呢? - immortal