C++ 如何让位字段按正确的顺序排列位?
首先,所讨论的应用程序总是在同一个处理器上,而编译器总是gcc,所以我不担心位字段不可移植C++ 如何让位字段按正确的顺序排列位?,c++,c,gcc,bit-fields,C++,C,Gcc,Bit Fields,首先,所讨论的应用程序总是在同一个处理器上,而编译器总是gcc,所以我不担心位字段不可移植 gcc布局位字段,使第一个列出的字段对应于字节的最低有效位。所以下面的结构,在a=0,b=1,c=1,d=1的情况下,得到一个值为e0的字节 struct Bits { unsigned int a:5; unsigned int b:1; unsigned int c:1; unsigned int d:1; } __attribute__((__packed__)); (实际上,这是
gcc布局位字段,使第一个列出的字段对应于字节的最低有效位。所以下面的结构,在a=0,b=1,c=1,d=1的情况下,得到一个值为e0的字节
struct Bits {
unsigned int a:5;
unsigned int b:1;
unsigned int c:1;
unsigned int d:1;
} __attribute__((__packed__));
(实际上,这是C++,所以我在谈论g++)< /p> 现在让我们假设a是一个六位整数
现在,我明白了为什么这行不通,但我编写了以下结构:struct Bits2 {
unsigned int a:6;
unsigned int b:1;
unsigned int c:1;
unsigned int d:1;
} __attribute__((__packed__));
将b、c和d设置为1,将a设置为0,将产生以下两个字节:
c0 01
这不是我想要的。我希望看到这个:
e0 00
有没有办法指定一个结构,该结构在第一个字节的最高有效位中有三位,在第一个字节的五个最低有效位和第二个字节的最高有效位之间有六位
请注意,我无法控制这些位应该放在何处:它是由其他人的接口定义的位布局。通常您无法对如何打包联合进行严格假设,每个编译器实现可能会选择不同的打包方式(以节省空间或对齐字节内的位字段) 我建议你只使用掩蔽和位运算符 发件人: 位字段的主要用途是允许数据紧密打包,或者能够在一些外部生成的数据文件中指定字段。C不保证机器字中字段的顺序,因此如果您出于后一个原因使用它们,那么您的程序不仅不可移植,而且依赖于编译器。Standard说字段被打包到“存储单元”中,通常是机器字。打包顺序以及位字段是否可以跨越存储单元边界都是实现定义的。要强制对齐到存储单元边界,在要对齐的字段之前使用零宽度字段
C/C++无法指定结构的逐位内存布局,因此需要对8位或16位(无符号)整数(来自
或
的uint8、uint16)进行手动位移位和屏蔽
在我所知道的十几种编程语言中,只有极少数允许您为位字段指定逐位内存布局:Ada、Erlang、VHDL(和Verilog)
(如果您想向该列表添加更多语言,请访问社区wiki。)(请注意,所有这些都是特定于gcc的注释-我很清楚,位字段的布局是由实现定义的)
不是在little endian机器上:问题是在little endian机器上,第二个字节的最高有效位不被认为与第一个字节的最低有效位“相邻”
但是,您可以将位字段与ntohs()
函数组合:
union u_Bits2{
struct Bits2 {
uint16_t _padding:7;
uint16_t a:6;
uint16_t b:1;
uint16_t c:1;
uint16_t d:1;
} bits __attribute__((__packed__));
uint16_t word;
}
union u_Bits2 flags;
flags.word = ntohs(flag_bytes_from_network);
但是,我强烈建议您避免使用位字段,而是使用移位和掩码。我想您的意思是“注意小端点”,而不是“不在小端点”.不过,我想我理解你的意思。在一台小小的endian机器上,位的邻接度取决于位如何打包到机器字中,编译器假设机器字将进行字节交换。我将听取其他人的建议,进行掩蔽和移位,但感谢你弄清楚这是怎么回事。是的-gcc将字内的位字段从最低位打包到最高位,在小端机上,最低8位存储在第一个字节中。“gcc布局位字段,使第一个列出的字段对应于一个字节的最低有效位。”否,gcc(在本例中,包括继承C实现定义的行为的
g++
)以ABI依赖的顺序排列位字段:。在您的体系结构上,这是否恰好是lsbit完全是偶然的。