草船借箭歇后语下一句:结构体对齐的具体含义|结构体,对齐,含义,fdsfdsa

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 08:16:37

最近對結構體對齊比較感興趣,收集了一些資料

结构体对齐的具体含义(#pragma pack)

                                      

#pragma pack (4)
  class TestB
  {
  public:
    int aa;
    char a;
    short b;
    char c;
  };
  int nSize = sizeof(TestB);
  这里nSize结果为12,在预料之中。

  现在去掉第一个成员变量为如下代码:
  #pragma pack (4)
  class TestC
  {
  public:
    char a;
    short b;
    char c;
  };
  int nSize = sizeof(TestC);
  按照正常的填充方式nSize的结果应该是8,为什么结果显示nSize为6呢?

事实上,很多人对#pragma pack 的理解是错误的。
#pragma pack 规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行。
也就是说,当#pragma pack 的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
而结构整体的对齐,则按照结构体中最大的数据成员 和 #pragma pack 指定值 之间,较小的那个进行。

具体解释
#pragma pack (4)
  class TestB
  {
  public:
    int aa; //第一个成员,放在[0,3]偏移的位置,
    char a; //第二个成员,自身长为1,#pragma pack (4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。
    short b; //第三个成员,自身长2,#pragma pack (4),取2,按2字节对齐,所以放在偏移[6,7]的位置。
    char c; //第四个,自身长为1,放在[8]的位置。
  };
这个类实际占据的内存空间是9字节
类之间的对齐,是按照类内部最大的成员的长度,和#pragma pack 规定的值之中较小的一个对齐的。
所以这个例子中,类之间对齐的长度是min(sizeof(int),4),也就是4。
9按照4字节圆整的结果是12,所以sizeof(TestB)是12。


如果
#pragma pack (2)
class TestB
  {
  public:
    int aa; //第一个成员,放在[0,3]偏移的位置,
    char a; //第二个成员,自身长为1,#pragma pack (4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。
    short b; //第三个成员,自身长2,#pragma pack (4),取2,按2字节对齐,所以放在偏移[6,7]的位置。
    char c; //第四个,自身长为1,放在[8]的位置。
  };
//可以看出,上面的位置完全没有变化,只是类之间改为按2字节对齐,9按2圆整的结果是10。
//所以 sizeof(TestB)是10。

最后看原贴:
现在去掉第一个成员变量为如下代码:
  #pragma pack (4)
  class TestC
  {
  public:
    char a;//第一个成员,放在[0]偏移的位置,
    short b;//第二个成员,自身长2,#pragma pack (4),取2,按2字节对齐,所以放在偏移[2,3]的位置。
    char c;//第三个,自身长为1,放在[4]的位置。
  };
//整个类的大小是5字节,按照min(sizeof(short),4)字节对齐,也就是2字节对齐,结果是6
//所以sizeof(TestC)是6。

 對於位域有如下規定:

C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。使用位域的主要目的是压缩存储,其大致规则为:
    1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
    2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
    3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
    4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
    5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

    还是让我们来看看例子。
    示例1:
struct BF1
{
    char f1 : 3;
    char f2 : 4;
    char f3 : 5;
};
    其内存布局为:
|_f1__|__f2__|_|____f3___|____|
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
0 3 7 8 1316
    位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只
能从下一个字节开始。因此sizeof(BF1)的结果为2。

    示例2:
struct BF2
{
    char f1 : 3;
    short f2 : 4;
    char f3 : 5;
};
    由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。

    示例3:
struct BF3
{
    char f1 : 3;
    char f2;
    char f3 : 5;
};
    非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。