【发布时间】: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 条,对于不基于 _Bool、int、signed int 或 unsigned 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