Leo*_*d99 54 c portability cross-platform low-level bit-fields
任何使用位域的可移植代码似乎都区分了小端和大端平台.有关此类代码的示例,请参阅linux内核中struct iphdr的声明.我无法理解为什么位字节序是一个问题.
据我所知,bitfields纯粹是编译器构造,用于促进位级操作.
例如,考虑以下位域:
只是一种简洁易懂的说法
struct ParsedInt {
unsigned int f1:1;
unsigned int f2:3;
unsigned int f3:4;
};
uint8_t i;
struct ParsedInt *d = &i;
d->f2.
但是,无论架构如何,位操作都是明确定义的并且可以正常工作.那么,bitfields怎么不便携?
Lun*_*din 72
根据C标准,编译器可以自由地以任何随机的方式存储位字段.您永远不能对位分配的位置做出任何假设.以下是C标准未指定的一些与位字段相关的事情:
未指定的行为
实现定义的行为
大/小端当然也是实现定义的.这意味着您的结构可以通过以下方式分配(假设16位整数):
PADDING : 8
f1 : 1
f2 : 3
f3 : 4
or
PADDING : 8
f3 : 4
f2 : 3
f1 : 1
or
f1 : 1
f2 : 3
f3 : 4
PADDING : 8
or
f3 : 4
f2 : 3
f1 : 1
PADDING : 8
Run Code Online (Sandbox Code Playgroud)
哪一个适用?猜测一下,或者阅读编译器的深入后端文档.添加大端或小端的32位整数的复杂性.然后添加一个事实,即允许编译器在位字段内的任何位置添加任意数量的填充字节,因为它被视为结构(它不能在结构的最开头添加填充,但在其他任何地方都添加填充).
然后我甚至没有提到如果你使用普通的"int"作为位字段类型=实现定义的行为,或者你使用除(unsigned)int =实现定义的行为之外的任何其他类型会发生什么.
因此,为了回答这个问题,没有便携式位域代码这样的东西,因为C标准对如何实现位字段非常模糊.可以信任的唯一比特字段是布尔值的块,其中程序员不关心存储器中位的位置.
唯一的可移植解决方案是使用逐位运算符而不是位字段.生成的机器代码将完全相同,但具有确定性.对于任何系统,按位运算符在任何C编译器上都是100%可移植的.
Mic*_*urr 16
据我所知,bitfields纯粹是编译器构造
这就是问题的一部分.如果位域的使用仅限于编译器"拥有"的内容,那么编译器如何打包或排序它们对任何人来说都不是什么问题.
但是,位域可能更常用于模拟编译器域外部的构造 - 硬件寄存器,通信的"线"协议或文件格式布局.这些东西对如何布局位有严格的要求,并且使用位域来建模它们意味着你必须依赖于实现定义的 - 更糟糕的是 - 编译器如何布局位域的未指定行为.
简而言之,位字段的指定不足以使它们对于它们似乎最常用的情况有用.
ISO/IEC 9899: 6.7.2.1/10
实现可以分配足够大的任何可寻址存储单元以保持比特字段.如果剩余足够的空间,则紧跟在结构中另一个位字段之后的位字段将被打包到同一单元的相邻位中.如果剩余的空间不足,则是否将不适合的位场放入下一个单元或重叠相邻单元是实现定义的.在一个单元内(高阶到低阶或低阶到高阶)的位字分配顺序是实现定义的.可寻址存储单元的对齐未指定.
使用位移操作更安全,而不是在尝试编写可移植代码时对位字段排序或对齐做出任何假设,无论系统字节顺序或位数如何.
另见EXP11-C.不要将期望一种类型的运算符应用于不兼容类型的数据.
位字段访问是根据对底层类型的操作实现的.在这个例子中unsigned int.所以如果你有类似的东西:
struct x {
unsigned int a : 4;
unsigned int b : 8;
unsigned int c : 4;
};
Run Code Online (Sandbox Code Playgroud)
访问字段时b,编译器访问整个unsigned int,然后移位并屏蔽相应的位范围.(当然,它不会有,但我们可以假装它.)
在big endian上,布局将是这样的(最重要的是第一位):
AAAABBBB BBBBCCCC
Run Code Online (Sandbox Code Playgroud)
在小端,布局将是这样的:
BBBBAAAA CCCCBBBB
Run Code Online (Sandbox Code Playgroud)
如果你想从小端访问大端布局,反之亦然,你将不得不做一些额外的工作.这种可移植性的增加具有性能损失,并且由于结构布局已经是不可移植的,因此语言实现者采用了更快的版本.
这做了很多假设.另请注意,sizeof(struct x) == 4在大多数平台上.