【问题标题】:Type of lvalue.bitfield when the underlying bitfield type is not int in C当底层位域类型不是 C 中的 int 时 lvalue.bitfield 的类型
【发布时间】:2011-09-13 19:54:54
【问题描述】:

有人提请我注意以下程序:

#include <stdio.h>

struct X50 {
 long long int z:50;
} s50 = { 2 };

struct X10 {
 long long int z:10;
} s10 = { 2 };

int main() {
  printf("%zu %zu %zu\n",sizeof(long long int),sizeof(s10.z+1),sizeof(s50.z+1));
}

表达式sizeof(lv.z+1) 的类型是根据“通常的算术转换”计算的,这几乎可以说左值lv.z 的类型大小将反映在加法的类型上,只要至少是int

我没想到这种类型会依赖于位域的大小,但确实如此:GCC 和 Clang 都在我的计算机上打印 8 4 8

我在 C99 标准中找到的相关条款是 6.3.1.1 中的第 2 条,对于不基于 _Boolintsigned intunsigned int 的位域,这似乎没有任何说明。子句的第二部分“如果 int 可以表示原始类型的所有值,则该值将转换为 int, ...”,似乎只适用于第一部分中描述的条件子句,不包括基于long long int 的位域。

此外,6.7.2.1 说:

位域的类型应为合格或不合格 _Bool、signed int、unsigned int 或其他一些版本 实现定义的类型。

是不是因为long long int 位域超出了标准的范围,编译器可以发明自己的规则,还是可以在 C99 的其他地方找到 Clang 和 GCC 行为的某种理由?

我在 StackOverflow 上找到了 this question,它指向“编译器可以发明自己的规则”的方向,但我仍然可能错过了 Clang 和 GCC 都将 S10.z 输入为 int 的理由。

【问题讨论】:

  • 其他问题的哪一部分说“标准中没有规定”不是您满意的答案?该标准并没有详细说明位域 - 您引用的基本上就是它 - 如果它说某些内容是“实现定义的”,它通常不会继续详细讨论它。跨度>
  • @Chris Lutz 我要强调的是,您链接的问题的答案并不能说明 GCC 和 Clang 的行为是否是标准施加的约束的结果,这与 @Chris Lutz 是否不是同一个问题987654337@ 位域是一种语言扩展(它们是)。
  • @Chris Lutz 为什么重要:我从事静态分析器工作,我不希望只对 GCC 和 Clang 程序有好处(尽管这些是我每天使用的编译器)。如果任何实现 long long 位域的 C99 编译器必须以与 GCC 相同的方式执行,我也将实现这些相同的规则。如果可以以不同的方式完成,我要么拒绝该扩展,要么永远担心另一个编译器将X10.z 类型为long long,而我的分析器预测使用该编译器编译的程序是错误的。
  • 检查标准后,我同意。我希望 SO 有一个更好的关闭/重新打开系统,可以让我撤回我的关闭投票。事实上,我已经发布了一个答案,其中包含我认为相关的部分标准。

标签: c c99 bit-fields


【解决方案1】:

6.7.2.1 第 10 段(强调):

一个实现可以分配任何大到足以容纳一个位的可寻址存储单元- 如果有足够的空间,一个位域紧跟在一个位域的另一个位域之后 结构应打包到同一单元的相邻位中。如果剩余空间不足, 不适合的位域是否放入下一个单元或与相邻单元重叠是 实现定义。一个单元内位域的分配顺序(高阶到 低阶或低阶到高阶)是实现定义的。对齐方式 未指定可寻址存储单元。

因此,在回答您的问题(我不再认为这是重复的问题)时,如果编译器允许将实现定义的类型用作位域的类型,则似乎不需要分配足够的该类型的大小,只有实际位域的足够大小。当然,它似乎也有权为位域分配 4 KB。

【讨论】:

  • 考虑到位域的“自然”类型是它在内存溢出时所存储的可寻址存储单元的类型,并且 C99 通常的算术转换原理只要求将其提升到 @ 987654321@ 进行操作,阅读您的答案后,GCC 的行为似乎更正常。但我仍然必须担心其他编译器的做法会有所不同。
  • 他们可能会采取不同的做法。根据标准,编译器只需要为位域分配足够的空间。所以看起来你只能保证sizeof(s10.z1 + 1) &gt;= sizeof(int)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
  • 2017-07-26
  • 1970-01-01
  • 2020-12-25
  • 1970-01-01
  • 2020-12-14
  • 2020-03-18
相关资源
最近更新 更多