包含位字段的结构的大小

时间:2012-10-06 17:18:13

标签: c++ c sizeof bit-fields structure-packing

  

可能重复:
  Why isn't sizeof for a struct equal to the sum of sizeof of each member?

我试图了解位字段的概念。 但我无法找到CASE III中以下结构的大小为8个字节的原因。

案例I:

struct B    
{
    unsigned char c;  // +8 bits
} b;

的sizeof(B); //输出:1(因为unsigned char在我的系统上占用1个字节)

案例II:

struct B
{
    unsigned b: 1;
} b;

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

案例III:

struct B
{
    unsigned char c;  // +8 bits
    unsigned b: 1;    // +1 bit
} b;

sizeof(b); // Output: 8 

我不明白为什么案例III的输出为8.我期待1(字符)+4(无符号)= 5.

6 个答案:

答案 0 :(得分:7)

您可以使用offsetof检查结构的布局,但它将是以下内容:

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.如果是字段{{ 1}}从偏移量4开始,长度为4个字节,然后结构的大小为8。

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

答案 1 :(得分:3)

我认为你在这里看到了alignment效果。

许多架构要求将整数存储在内存中多个字长的地址上。

这就是为什么第三个结构中的char被填充三个字节的原因,以便后面的无符号整数从一个字长的倍数开始。

答案 2 :(得分:2)

Char定义为一个字节。 int是32位系统上的4个字节。并且结构被填充额外的4。

有关填充的一些解释,请参阅http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86

答案 3 :(得分:1)

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

答案 4 :(得分:1)

结构的对齐和总大小是平台和编译器特定的。你不能不期望在这里得到直截了当和可预测的答案。编译器总能有一些特别的想法。例如:

struct B
{
    unsigned b0: 1;    // +1 bit
    unsigned char c;  // +8 bits
    unsigned b1: 1;    // +1 bit
};

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

struct B
{
    unsigned short c, d, e;
};

由编译器打包/不打包此结构的字段(假设32位平台)。结构的布局可以在DEBUG和RELEASE构建之间有所不同。

我建议只使用以下模式:

struct B
{
    unsigned b0: 1;
    unsigned b1: 7;
    unsigned b2: 2;
};

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

答案 5 :(得分:1)

我再看看这个,这就是我找到的。

  1. 从C书中,“几乎所有关于字段的内容都与实现有关。”
  2. 在我的机器上:
  3.  struct B {
        unsigned c: 8;
        unsigned b: 1;
    }b;
    printf("%lu\n", sizeof(b));
    

    打印4这是一个简短的;

    您正在将位字段与常规struct元素混合使用。

    BTW,位字段被定义为:“在一个主题实现定义的存储单元中的一组相邻的”所以,我甚至不确定':8'是做什么的你要。这似乎不符合比特字段的精神(因为它不再是一点点)