关于c ++:包含位字段的结构的大小

size of a structure containing bit fields

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why isn't sizeof for a struct equal to the sum of sizeof of each member?

我试图理解位场的概念。但我不明白为什么在第三种情况下,下面的结构的大小是8字节。

案例一:

1
2
3
4
struct B    
{
    unsigned char c;  // +8 bits
} b;

sizeof(b);//输出:1(因为无符号字符在我的系统上占用1个字节)

案例二:

1
2
3
4
5
6
struct B
{
    unsigned b: 1;
} b;

 sizeof(b); // Output: 4 (because unsigned takes 4 bytes on my system)

III案:

1
2
3
4
5
6
7
struct B
{
    unsigned char c;  // +8 bits
    unsigned b: 1;    // +1 bit
} b;

sizeof(b); // Output: 8

我不明白为什么案例三的输出是8。我期待着1(char)+4(unsigned)=5。


您可以使用offsetof来检查结构的布局,但它将是沿着以下几条线的:

1
2
3
4
5
6
struct B
{
    unsigned char c;  // +8 bits
    unsigned char pad[3]; //padding
    unsigned int bint; //your b:1 will be the first byte of this one
} b;

现在,很明显(在一个32位的拱门中)sizeof(b)将是8,不是吗?

问题是,为什么要填充3个字节,而不是更多或更少?

答案是,字段到结构的偏移量与字段本身的类型具有相同的对齐要求。在您的体系结构中,整数是4字节对齐的,所以offsetof(b, bint)必须是4的倍数。它不能是0,因为之前有c,所以它是4。如果字段bint从偏移量4开始,长度为4字节,则结构的大小为8。

另一种看它的方法是,结构的对齐要求是它的任何字段中最大的,所以这个B将是4字节对齐的(因为它是您的位字段)。但是一个类型的大小必须是对齐的倍数,4是不够的,所以它将是8。


我想你在这里看到了一个对齐效果。

许多体系结构要求将整数存储在内存中的多个字大小的地址中。

这就是为什么第三个结构中的char被另外三个字节填充,以便下面的无符号整数从一个单词大小的倍数地址开始。


字符的定义是一个字节。整数是32位系统上的4个字节。结构正在被额外的4个填充。

有关填充的一些解释,请参见http://en.wikipedia.org/wiki/data_-structure_-alignment典型的_-c-structs_-on-x86


我又看了一眼,这是我发现的。

  • 在C书中,"几乎所有关于字段的内容都依赖于实现。"
  • 在我的机器上:
  • 1
    2
    3
    4
    5
    6
     struct B {
        unsigned c: 8;
        unsigned b: 1;
    }b;
    printf("%lu
    "
    , sizeof(b));

    打印4,简称4;

    您正在将位字段与常规结构元素混合。

    顺便说一句,位字段定义为:"Sindle实现中的一组相邻位定义了存储单元",因此,我甚至不确定":8"是否满足您的需要。这似乎不符合比特场的精神(因为它不再是比特场了)


    结构的对齐方式和总大小是平台和编译器特有的。在这里,你不可能期望得到直接而可预测的答案。编译器总是有一些特殊的想法。例如:

    1
    2
    3
    4
    5
    6
    struct B
    {
        unsigned b0: 1;    // +1 bit
        unsigned char c;  // +8 bits
        unsigned b1: 1;    // +1 bit
    };

    编译器可以将字段b0和b1合并为一个整数,但不能合并。这取决于编译器。有些编译器有控制这个的命令行键,有些编译器没有。其他例子:

    1
    2
    3
    4
    struct B
    {
        unsigned short c, d, e;
    };

    由编译器来打包/不打包这个结构的字段(即32位平台)。结构的布局在调试和发布版本之间可能有所不同。

    我建议只使用以下模式:

    1
    2
    3
    4
    5
    6
    struct B
    {
        unsigned b0: 1;
        unsigned b1: 7;
        unsigned b2: 2;
    };

    当您有共享同一类型的位字段序列时,编译器会将它们放入一个int中,否则各个方面都会起作用。还要考虑到,在一个大型项目中,您编写一段代码,其他人将编写和重写makefile;将代码从一个dll移动到另一个dll。此时将设置和更改编译器标志。99%的人可能不知道您的结构的对齐要求。他们甚至不会打开你的文件。


    为了保持对内存的访问保持一致,编译器正在添加填充。如果对结构进行打包,它将不会添加填充。