为什么一个位字段的类型影响包含结构体的大小?(Why would the type of a bit

2019-08-22 12:35发布

首先,这里是ISO C标准说,大约位字段,引用了N1570的2011 ISO C标准的草案,部分6.7.2.1:

位域应具有类型,它是一个合格的或不合格的版本_Boolsigned intunsigned int ,或其他一些实现定义的类型。 它是实现定义的原子类型是否是允许的。

...

位字段被解释为具有由位的指定数量的符号或无符号整数类型。 如果该值为0或1被存储到类型的非零宽度位字段_Bool ,位字段的值应比较等于所存储的值; 一个_Bool位字段具有的语义_Bool

实现可分配任何可寻址存储单元,大到足以容纳一个比特字段。 如果有足够的空间保持,紧跟在一个结构中的另一位字段位字段应包装到同一单元的相邻比特。 如果没有足够的空间仍然存在,不适合的位字段是否被放入下一个单元或重叠相邻单元是实现定义。 一个单元(高位到低位或低阶到高阶)内的位字段的分配顺序是实现定义。 在可寻址存储单元的取向是不确定的。

对于任何struct类型,该类型的对准是至少所述类型的任何成员的最大对齐,以及任何类型的大小是它的对准的倍数。 例如,如果一个结构包含一个(非位字段) int构件,并且int需要4字节对齐,则结构本身需要4字节对齐以上。

许多编译器允许比其他整数类型的位字段_Boolint类型。

对于至少一些编译器,一个的取向struct含有一个比特字段是至少声明类型的位字段的对准。 例如,对于在x86_64 GCC 4.7.2,因为:

struct sb {
    _Bool bf:1;
};
struct si {
    unsigned bf:1;
};

GCC给出struct sb 1个字节(它的大小和对准的尺寸和对准_Bool ),和struct si的尺寸和4个字节对齐(其大小和取向int )。 它具有实现定义类型的位字段同样的事情; 定义为一个比特字段long long bf:1; 强制为封闭结构的8字节大小和对齐。 这样做,即使在两种情况下,位字段bf是一个对象,其宽度只有1位。

我已经看到了与Sun的SPARC上/ Solaris中9编译器类似的行为。

实验结果表明,多比特字段定义成_Bool或作为unsigned (在的需要的事实)可装入相邻比特在一个字节中,所以位字段本身不具有严格的对准要求。

据我所知,结构构件的配置主要是实现定义的,我不相信,海湾合作委员会的行为违反了C标准。

所以我的问题( 终于!)是的,为什么不GCC(至少有一个不相关的C编译器,可能更一起)做到这一点? 不要GCC的作者认为,一个位字段声明的类型必须影响包含结构的大小和定位? 他们是这个假设是正确的? 有没有在C标准本身的要求,我已经错过了吗?

下面是表现出行为的测试程序。 如果你想你的系统上运行它,您可能需要注释掉它的部分,如果您使用的是旧的编译器不支持一些新功能,或一个不允许某些类型的位领域。 如果有作为的行为确实GCC编译器我有兴趣知道。

#include <stdio.h>
#include <limits.h>
#include <stdint.h>
int main(void) {
    struct sb  { _Bool    bf:1; };
    struct s8  { uint8_t  bf:1; };
    struct s16 { uint16_t bf:1; };
    struct s32 { uint32_t bf:1; };
    struct s64 { uint64_t bf:1; };
    printf("sizeof (struct sb)  = %2zu (%2zu bits)\n",
           sizeof (struct sb),
           sizeof (struct sb)  * CHAR_BIT);
    printf("sizeof (struct s8)  = %2zu (%2zu bits)\n",
           sizeof (struct s8),
           sizeof (struct s8)  * CHAR_BIT);
    printf("sizeof (struct s16) = %2zu (%2zu bits)\n",
           sizeof (struct s16),
           sizeof (struct s16) * CHAR_BIT);
    printf("sizeof (struct s32) = %2zu (%2zu bits)\n",
           sizeof (struct s32),
           sizeof (struct s32) * CHAR_BIT);
    printf("sizeof (struct s64) = %2zu (%2zu bits)\n",
           sizeof (struct s64),
           sizeof (struct s64) * CHAR_BIT);
    return 0;
}

这里的输出我得到我的系统上:

sizeof (struct sb)  =  1 ( 8 bits)
sizeof (struct s8)  =  1 ( 8 bits)
sizeof (struct s16) =  2 (16 bits)
sizeof (struct s32) =  4 (32 bits)
sizeof (struct s64) =  8 (64 bits)

Answer 1:

在某种程度上,你自己回答了这个问题与标准这段话:

在可寻址存储单元的取向是不确定的。

编译器可以选择任何定位,坚持以C标准,但是这并不是故事的全部。

为了让代码不同的编译器进行互操作编制,平台ABI必须指定这些细节。 例如,通过Linux x86上使用SYS-V的i386 ABI说:

位字段服从相同的尺寸和对准规则为其他结构和联合成员,并有以下补充:[...]

  • 位字段必须完全驻留在适合其声明的类型的存储单元。

那么它遵循无论宽度,一个long位字段必须驻留在东西是一个4字节边界上对齐。



文章来源: Why would the type of a bit field affect the size of the containing structure?
标签: c gcc struct