包含位域的结构的大小

可能重复:
为什么structof sizeof不等于每个成员的sizeof总和?

我试图理解位域的概念。 但我无法找到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(char)+ 4(无符号)= 5。

您可以使用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.如果field bint从offset 4开始并且是4个字节长,然后结构的大小是8。

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

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

许多体系结构要求将整数存储在存储器中的地址中,该地址是字大小的倍数。

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

根据定义,字符是一个字节。 int是32位系统上的4个字节。 并且结构正在填充额外的4。

有关填充的一些说明,请参见http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86

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

我再看看这个,这就是我发现的。

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

打印4这是一个简短的;

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

顺便说一下,位字段定义为:“一个主轴实现定义的存储单元中的一组相邻 ”所以,我甚至不确定’:8’是否符合您的要求。 这似乎不符合位域的精神(因为它不再是一点点)

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

 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%的可能性是那些人不知道你的结构的对齐要求。 他们甚至都不打开你的文件。