尽管ANSI C标准对如何打包位域的规定太少了,与“允许编译器打包但认为合适的位域”相比,提供任何显着的优势,但是在许多情况下,它还是禁止编译器以最有效的方式打包内容。
特别地,如果结构包含位域,则要求编译器将其存储为包含某个或多个“正常”存储类型的匿名字段的结构,然后在逻辑上将每个此类字段细分为其组成的位字段部分。因此,给出:
unsigned char foo1: 3;
unsigned char foo2: 3;
unsigned char foo3: 3;
unsigned char foo4: 3;
unsigned char foo5: 3;
unsigned char foo6: 3;
unsigned char foo7: 3;
如果unsigned char
为8位,则要求编译器分配该类型的四个字段,并为除一个字段之外的所有字段分配两个位字段(它们将位于char
其自己的字段中)。如果所有char
声明都已替换为short
,那么将有两个类型的字段short
,其中一个字段将包含五个位域,而另一个字段将保留其余两个位域。
在没有对齐限制的处理器上,可以通过使用unsigned short
前五个字段和unsigned char
后两个字段(三个字节存储七个三位字段)来更有效地布局数据。尽管应该可以在三个字节中存储八个三位字段,但是编译器只能允许存在一个可用作“外部字段”类型的三字节数字类型。
我个人认为定义的位域基本上是无用的。如果代码需要处理二进制打包的数据,则应明确定义实际类型的存储位置,然后使用宏或其他某种方式访问其位。如果C支持以下语法,则将很有帮助:
unsigned short f1;
unsigned char f2;
union foo1 = f1:0.3;
union foo2 = f1:3.3;
union foo3 = f1:6.3;
union foo4 = f1:9.3;
union foo5 = f1:12.3;
union foo6 = f2:0.3;
union foo7 = f2:3.3;
这样的语法(如果允许)将使代码能够以可移植的方式使用位域,而无需考虑字长或字节顺序(foo0将位于f1的三个最低有效位,但是可以将它们存储在较低或较高的地址)。但是,缺少这种功能,宏可能是处理此类问题的唯一可移植方式。