有人提醒我注意以下计划:
#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
作为{ {1}}。
答案 0 :(得分:3)
6.7.2.1第10段(强调增加):
一个实现可以分配任何足够大的可寻址存储单元来保存位 - 字段。如果剩余足够的空间,则紧跟在a中的另一个位字段之后的位字段 结构应打包到同一单元的相邻位。如果剩余的空间不足, 是否将不适合的位域放入下一个单元或重叠相邻单元 实施德网络定义。一个单元内的位域分配顺序(高位到 实现定义的是低阶或低阶到高阶。对齐 可寻址存储单元未指定。
因此,在回答您的问题(我不再认为是重复的)时,如果编译器允许将实现定义的类型用作位域的类型,则似乎不需要分配足够的类型的大小,只有实际位域的大小。当然,它也有权为bitfield分配4千字节。