即使尽管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
,可以更有效地布置数据,以三个字节存储七个三位字段。虽然应该可以将三个字节的8位三位字段存储起来,但编译器只允许在存在可以用作“外部字段”类型的三字节数字类型的情况下。
就个人而言,我认为位域定义为基本无用。如果代码需要使用二进制打包数据,它应该明确定义实际类型的存储位置,然后使用宏或其他一些手段访问其中的位。这将是有益如果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的三个最低有效位中,但可以存储在较低或较高地址)。但是,如果没有这样的功能,宏可能是唯一可以使用这种操作的便携式方式。
这可能是对齐的优化。如果下一个比特大小不适合实际占用的空间,它将启动一个新的字节。 – 2014-11-02 13:52:42
除非您有一些外部约束需要位打包,并且您的平台为标准提供了一些额外的保证,否则使用位域几乎没有意义。 – 2014-11-02 15:35:36
请注意,对于C来说,使用char不如使用int可移植,http://stackoverflow.com/a/23987436/23118。 – hlovdal 2014-11-02 15:41:52