【问题标题】:Use of zero-width fields for bit-field alignment使用零宽度字段进行位字段对齐
【发布时间】:2016-09-12 08:26:19
【问题描述】:

在 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 不能打包到同一个(非存储)同上一个。

我的编译器似乎确实忽略了额外的内容,但我想知道规范是否确实保证了这一点。

【问题讨论】:

  • 你的编译器告诉你什么?
  • @alk 在这一点上无关紧要 - 问题是 标准 告诉我什么(目前很少)
  • 为什么不去那里看看呢? port70.net/~nsz/c/c11/n1570.html#3.14p3
  • 关于位字段的内容实际上是特定于实现的,我不希望在标准中找到任何指导。
  • 我认为:0 位字段将填充零位或更多位以实现所需的对齐。如果它已经对齐,则填充量为零。这个想法不是跳过,而是填充最小量以实现所需的对齐。对齐后,后续的:0 位字段(具有相同的大小类型说明符)应该无效。

标签: c language-lawyer bit-fields


【解决方案1】:

不,不保证符合规范。

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

由于:0 本身不是位字段,因此您正在冗余地定义该属性。由于该标准并未专门解决此问题,因此它是“未定义”行为,您不能期望它在各种实现中始终如一地工作。

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

如果“应”或“不应”要求出现在 违反约束,行为未定义。未定义的行为 在本国际标准中另有说明 “未定义的行为”或省略任何明确的定义 行为。这三者在侧重点上没有区别:它们 都描述了“未定义的行为”

~ 未定义的行为 (§3.16) C90

【讨论】:

  • @M.M 谢谢!已更正。
  • 问题是:“如果声明两个连续的零宽度字段 [?]”,是否有定义的行为? - 因此我支持这个(更正)回答。
  • 不明确的措辞并不意味着未定义的行为。问题中引用的段落试图定义行为。鉴于规范是英文的,而不是形式逻辑之类的,总会有这样的情况。
  • 引用的段落确实定义了行为。它没有解决以这种方式重复应用属性的问题。如果您想要一个“empty”对齐的位域,之后,您必须定义一个有效的(:1 或更大)位域,然后再次定义:0。因此它仍然是 undefined -- 没有符合标准的编译器应该实现问题中提到的想象行为。
【解决方案2】:

无论您是否将零长度位字段算作实际位字段,您都可以说,它总是与之前的字段放在同一个打包单元中。因为那是它影响的包装单元:它基本上填满了它,因此不能在其中放置更多位。而且,如果前面的字段已经满了,虚拟字段就没有任何作用。另一方面,虚拟字段不会以任何方式影响后面的打包单元,因为它仍然完全可以被比特填充。

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

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

【讨论】:

  • 听起来不错,除了第一个位字段是否为int :0;“它基本上填满了它,因此不能在其中放置更多位”--> 没有“它”或“之前的字段”来填写。但我喜欢这个答案。
  • 有趣的是,我对几乎相同的答案投了反对票。我要把矛头指向你:language_lawyer = site_standard;
  • @veganaiZe:我没有对你投反对票,我认为你的回答不值得。但是,当我阅读您的答案时,困扰我的是将该问题称为“未定义”。通常,当我们处理未定义的行为时,所讨论的行为是由标准本身明确声明为未定义的,这里绝对不是这种情况。感觉更像是措辞中的一个(部分)漏洞,我相信它指向一个关于如何解释的单一方向。请注意,我的回答完全与标准的措辞争论,所以我相信这是一个有效的语言律师回答。
  • @cmaster 尽管我同意你的观点(一方面),但该标准专门解决了此类问题——无论我们是否接受。考虑仔细重新阅读我的引文。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
  • 2012-02-28
  • 2020-07-19
  • 1970-01-01
相关资源
最近更新 更多