#pragma pack(n)的含义及其用法

Koder
        下面这篇文章详细介绍了关于内存处理中字节对齐。结构体 或者 类 存在字节对齐的问题,这个问题的理解需要对内存中数据的存放等有深刻的理解。是工程项目中经常需要用到的。
---------------------------------------------------------------------------------------------------

 #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的理解是错误的。

关于struct的使用方法

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

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

#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字节对齐,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。

在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了

字节对齐可以用取余的方式来处理。

例如#pragma pack(4) 如果结构体中有short 类型的数据 则去 min(sizeof(short), 4)为short的字节对齐边界。 sizeof(short) = 2; 所以存放该数据的内存的地方需要是 mem % 2 == 0 的地方。

在做这些处理的时候, 可以画图的方式来看比较清晰。

windows下面默认的是#pragma pack(8)
所以如果要紧凑内存存放的话 需要用 #pragma pack(1)来限制了。

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

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

你可能感兴趣的:(用法)