为什么GCC填充这个位域?

程序在C中使用std = c99,这是在64位机器上。

struct epochs { volatile unsigned int epoch : 1; volatile unsigned int pulse : 1; volatile unsigned int active0 : 7; volatile unsigned int active1 : 7; volatile unsigned int counter0 : 24; volatile unsigned int counter1 : 24; }; 

当我检查sizeof(epochs)它给了我12。

我可以告诉gcc不要通过添加__attribute((packed))来填充它; 所以我可以解决它。 但是我真的想知道为什么要添加4个字节来填充这个64位结构?

这里的主要内容是这个结构需要64位,因为它在64位primefaces交换操作中一次更新,当然这对12字节值不起作用。

 volatile unsigned int epoch : 1; volatile unsigned int pulse : 1; volatile unsigned int active0 : 7; volatile unsigned int active1 : 7; 

^ 32位(4字节)

 volatile unsigned int counter0 : 24; 

^ 32位(4字节)

 volatile unsigned int counter1 : 24; 

^ 32位(4字节)

所以多4个字节。

C说:

(C99,6.7.2.1p10)“如果剩余足够的空间,则紧跟在结构中另一个位域之后的位域应被打包到同一单元的相邻位中”

没有足够的空间将24位( counter0 )放在32位单元中(可能是系统中unsigned int的大小)已经保持16位( epochpulseactive0active0 )。

您可以使用uin64_t而不是使用unsigned int以64位为单位打包您的位字段,但无论您的系统是否支持,它都是实现定义的。

(C99,6.7.2.1p4)“位字段的类型应为_Bool,signed int,unsigned int 或其他实现定义类型的限定或非限定版本。”

虽然一些较旧的编译器曾经认为int foo:3; 与例如long foo:3short foo:3同义,并且简单地以任何方便的方式放置foo ,本C标准规定每个位字段必须完全适合于适当大小的存储单元。 我不知道该规范的基本原理是什么,因为指定位字段的方式仍然过于模糊,无法在便携式代码中使用,但有时无法以最佳方式打包。 例如,24位值可以有效地存储在结构中的唯一方法是在一台支持32位整数的机器上有一台机器,或者有一个8位数据可以放在相邻的位置。 24位值(前面或后面),以“填写”一个32位字。

幸运的是,在您的特定情况下,可以通过重新排列字段来避免效率低下。 如果你的编译器支持使用这种类型的位域,那么也可以通过将每个字段的声明类型更改为unsigned long long来避免效率低下[在这种情况下,如果它们没有,则允许位字段跨越32位边界t跨越64位边界]。