在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
不能打包到与前一个相同的(非存储)。
我的编译器看起来似乎忽略了额外的,但我想知道这是否实际上符合规范。
答案 0 :(得分:2)
无论您是否将零长度位字段计为实际位字段,您可以说,它始终与之前的字段放在同一个打包单元中。因为这是它影响的包装单元:它基本上填满了它,因此不会在其中放置更多的位。并且,如果前一个字段已满,则虚拟字段无效。另一方面,虚拟字段不会以任何方式影响下面的打包单元,因为它仍然可以完全填充位。
因此,您观察到的忽略行为似乎是强制性的:在任何一种情况下,第二个:0
的前一个字段都在包含最后一个实际字段的打包单元中,与前一个字段是否相关被认为是最后一个实际字段,或前面的零长度字段。
话虽如此,这绝对是一个措辞极端案例,很可能是编写标准的人没有预料到的,因此其措辞确实不准确。因此,我不会通过一些编译器以另一种方式解释措辞。因此,我建议不要依赖int :0; int :0;
的任何特定行为。
答案 1 :(得分:-1)
它实际上是前一个位字段编译器的标志。它指示编译器通过用零填充来填充/对齐该位字段。
由于:0
本身不是位字段,因此您将冗余地定义该属性。由于该标准没有专门解决这个问题,因此它是“未定义”行为,您不能指望它在各种实现中一致地工作。
例如:一个编译器实现可能会默默地忽略它,而另一个实现可能会因为错误而破坏编译。
如果“必须”或“不应”要求出现在a。之外 违反了约束,行为未定义。未定义的行为 在本国际标准中另有说明 “未定义的行为”或遗漏任何明确的定义 行为即可。这三者的重点没有区别:他们 都描述了“未定义的行为”
〜未定义的行为(§3.16)C90