包含位字段的结构的大小

size of a structure containing bit fields

本文关键字:结构 包含位 字段      更新时间:2023-10-16

可能的重复:
为什么不是';t结构的sizeof等于每个成员的sizeof之和?

我试图理解位字段的概念。但我不知道为什么CASE III中以下结构的大小是8字节。

情况I:

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

大小(b);//输出:1(因为无符号字符在我的系统上占用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(unsigned)=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。如果字段bint从偏移量4开始,长度为4字节,则结构体的大小为8。

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

我认为您在这里看到了对齐效果。

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

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

Char根据定义是一个字节。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("%lun", sizeof(b));

打印4,这是一个短;

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

顺便说一句,位字段被定义为:"在一个sindle实现定义的存储单元内的一组相邻的"所以,我甚至不确定":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%的可能性是这些人不知道你的结构的对齐要求。他们甚至永远不会打开你的文件。