结构体对齐的具体含义(#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,为什么结果显示nSize6呢?

事实上,很多人对#pragma pack的理解是错误的。

 

关于struct的使用方法

struct是一种复合数据类型,其构成元素既可以是基本数据类型(如intlongfloat等)的变量,也可以是一些复合数据类型(如arraystructunion等)的数据单元。对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率。缺省情况下,编译器为结构体的每个成员按其自然对界(natural alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

 自然对界是指按结构体的成员中size最大的成员对齐。

 

#pragma pack规定的对齐长度,实际使用的规则是:

结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和结构体的自然对齐长度中比较小的那个进行。

也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。

结构体的对齐,按照结构体中size最大的数据成员和#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字节对齐,92圆整的结果是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

Linux下面就是

#define __PACKED_ATTR       __attribute__ ((__packed__))

 

typedef struct {

        char p[3] __PACKED_ATTR;

        long i __PACKED_ATTR;

} test ;

 

typedef struct {

        char p[3];

        long i;

} test1;

 

gcc test.c 编译后,它们的大小就是7,8

 

 

windows下面默认的是#pragma pack8

因为编译器在编译时会对程序进行优化,以便加快访问速度,所以一般都会按照2的倍数进行字节对齐。用这个宏就是为了防止编译器对结构的定义进行对齐。

#pragma(push,n)用来设置警告消息的等级

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值