如果我有16位表示3对值,每个5位长,另一个1位值,按照这个顺序,使用位域来描述它是否安全? ANSI C 是否保证这些位完全符合我指定的顺序?
struct {
unsigned v1 : 5;
unsigned v2 : 5;
unsigned v3 : 5;
unsigned v4 : 1;
} test;
如果没有,是否有其他数据结构可用于表示此问题?或者我应该只存储两个8位char
并以编程方式操作它们以确保可移植性?
答案 0 :(得分:4)
我能找到的相关引用是6.7.2.1(1),来自C99:
实现可以分配任何足够大的可寻址存储单元来保存位 - 领域。如果剩余足够的空间,则紧跟在a中的另一个位字段的位字段 结构应打包到同一单元的相邻位。如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的。单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的。可寻址存储单元的对齐未指定。
我认为unsigned
实际上不是“底层单位”类型,而是它只是位域声明本身的一部分:T : n
表示“取 n T
类型的位。真正的问题是,实施是否必需来选择“大”单位。例如,它可以通过使单位成为char
来使用三个字节;一个用于v1
,一个用于v2
,最后一个用于v3, v4
。或者它可以使单位为16位整数,在这种情况下,只需要使用一个单位。
正如您所指出的那样,单位内的位字段的排序未指定。 C中的数据原子单位是地址,而位域没有地址。保证struct成员的地址按声明的顺序增加,但是你不能对位域做出这样的声明(只关于它们的底层单位)。
答案 1 :(得分:1)
您可以使用uint16_t
中的stdint.h
类型,该类型保证是无符号16位数量的类型同义词。如果你担心字节序,那就会变得更复杂。
答案 2 :(得分:0)
除了位字段的实现定义方面之外,您可能还需要添加一个pragma或其他编译器指令来告诉编译器不要插入任何填充位。
以下是我刚才写的关于如何使用位字段从字节值中提取一些位的答案。当我写这篇文章时,我发现我需要添加#pragma pack(1)
,否则我的位字段不适合单个字节。
此答案还说明了如何使用union
将数据作为完整字节或位字段进行访问。您可以使用相同的技术以短整数或位字段的形式访问数据。