使用零宽度字段进行位域对齐

时间:2016-05-16 14:00:14

标签: c language-lawyer bit-fields

在C中,通过指定一个没有名称的零宽度位字段,可以强制一组位字段相对于其前一个存储单元在新存储单元上启动,例如

int field1:10;
int :0;
int field2:5;   // will be in a new storage unit

如果声明了两个连续的零宽度字段,例如:

,是否存在定义的行为
int field1:10;
int :0;
int :0;
int field2:5;   // will be in a new storage unit

在查看C90和C99规范时,我看不到任何明确指定是否忽略附加字段的任何内容,或者是否可能导致另外一个存储单元被搁置。

C99标准说(§6.7.2.1):

  

作为特殊情况,宽度为0的位域结构成员   表示不会将其他位字段打包到放置了前一位字段(如果有)的单元中。

我的阅读含糊不清 - 如果你将:0视为“虚拟”位字段(虽然没有占用任何存储空间),那么可以阅读上面的内容,说明下一个:0不能打包到与前一个相同的(非存储)。

我的编译器看起来似乎忽略了额外的,但我想知道这是否实际上符合规范。

2 个答案:

答案 0 :(得分:2)

无论您是否将零长度位字段计为实际位字段,您可以说,它始终与之前的字段放在同一个打包单元中。因为这是它影响的包装单元:它基本上填满了它,因此不会在其中放置更多的位。并且,如果前一个字段已满,则虚拟字段无效。另一方面,虚拟字段不会以任何方式影响下面的打包单元,因为它仍然可以完全填充位。

因此,您观察到的忽略行为似乎是强制性的:在任何一种情况下,第二个:0的前一个字段都在包含最后一个实际字段的打包单元中,与前一个字段是否相关被认为是最后一个实际字段,或前面的零长度字段。

话虽如此,这绝对是一个措辞极端案例,很可能是编写标准的人没有预料到的,因此其措辞确实不准确。因此,我不会通过一些编译器以另一种方式解释措辞。因此,我建议不要依赖int :0; int :0;的任何特定行为。

答案 1 :(得分:-1)

不,根据规范不能保证。

它实际上是前一个位字段编译器的标志。它指示编译器通过用零填充来填充/对齐该位字段。

由于:0本身不是位字段,因此您将冗余地定义该属性。由于该标准没有专门解决这个问题,因此它是“未定义”行为,您不能指望它在各种实现中一致地工作。

例如:一个编译器实现可能会默默地忽略它,而另一个实现可能会因为错误而破坏编译。

  

如果“必须”或“不应”要求出现在a。之外   违反了约束,行为未定义。未定义的行为   在本国际标准中另有说明   “未定义的行为”或遗漏任何明确的定义   行为即可。这三者的重点没有区别:他们   都描述了“未定义的行为”

     

未定义的行为(§3.16)C90