gcc 中的位域字节顺序
Bitfield endianness in gcc
位域的字节顺序是实现定义的。有没有办法在编译时通过某些宏或其他编译器标志检查 gcc 的位域字节序实际上是什么?
换句话说,给定如下:
struct X {
uint32_t a : 8;
uint32_t b : 24;
};
有没有办法让我在编译时知道 a
是X
中的第一个字节还是最后一个字节?
在 Linux 系统上,您可以检查 __BYTE_ORDER
宏以查看它是 __LITTLE_ENDIAN
还是 __BIG_ENDIAN
。虽然这不是权威的,但在实践中它应该有效。
在 netinet/ip.h 中 struct iphdr
的定义中暗示这是正确的方法,它用于 IP header。第一个字节包含两个 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. */
};
当位域是 8 位的倍数时,架构的字节顺序似乎并不重要。
参见here[godbolt.org]
我在这个godbolt示例中选择了arm架构,因为它支持big endian和little endian,并且很容易比较差异。
请注意,无论架构是大端还是小端,在这两种情况下,8 位字段都位于结构的开头。
我在 godbolt 上测试了所有可以为 is_8bit_tag_at_start 函数生成可读汇编代码的编译器,它们似乎都 return 正确。
位域的字节顺序是实现定义的。有没有办法在编译时通过某些宏或其他编译器标志检查 gcc 的位域字节序实际上是什么?
换句话说,给定如下:
struct X {
uint32_t a : 8;
uint32_t b : 24;
};
有没有办法让我在编译时知道 a
是X
中的第一个字节还是最后一个字节?
在 Linux 系统上,您可以检查 __BYTE_ORDER
宏以查看它是 __LITTLE_ENDIAN
还是 __BIG_ENDIAN
。虽然这不是权威的,但在实践中它应该有效。
在 netinet/ip.h 中 struct iphdr
的定义中暗示这是正确的方法,它用于 IP header。第一个字节包含两个 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. */
};
当位域是 8 位的倍数时,架构的字节顺序似乎并不重要。
参见here[godbolt.org]
我在这个godbolt示例中选择了arm架构,因为它支持big endian和little endian,并且很容易比较差异。
请注意,无论架构是大端还是小端,在这两种情况下,8 位字段都位于结构的开头。
我在 godbolt 上测试了所有可以为 is_8bit_tag_at_start 函数生成可读汇编代码的编译器,它们似乎都 return 正确。