内存对齐

内存对齐由编译器负责,编译器为程序中的每个"数据单元"安排在适当的位置上。

内存对齐原因:

   (1)平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

  (2)性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

内存对齐规则:

  每个特定平台上的编译器都有自己的默认"对齐系数"(也叫对齐模数)。32位编译器默认4字节,64位编译器默认8字节。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的"对齐系数"。

1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

3、结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

内存的自然对齐:每一种数据类型都必须放在地址中的整数倍上 

例如:

地址4可以放char(1)类型,可以放int(4)型,可以放short(2)型,但是不能存放double(8)型,仅仅因为4不是8的整数倍。 
地址3能存放char型,但是其他int,short,double都不能存放。 
有一个特殊地址,就是0,它可以是任何类型的整数倍,所以可以存放任何数据。 

结构体内存分配原则:

1.结构体的总大小,必须要是其内部最大成员的整数倍。

2..结构体或union联合的数据成员,第一个数据成员是要放在offset == 0的地方,如果遇上子成员,要根据子成员的类型存放在对应的整数倍的地址上 
3..如果结构体作为成员,则要找到这个结构体中的最大元素,然后从这个最大成员的整数倍地址开始存储(strutc a中有一个struct b,b里面有char,int,double….那b应该从8的整数倍开始存储)

4. 结构体或类的静态成员变量不计算在内存对齐中, sizeof只计算栈内分配内存

例如

class Base{
    int a;
    static double b;
    char c;
};
double Base::b = 0;
cout << sizeof(Base); // 值为8
原文地址:https://www.cnblogs.com/dj0325/p/8491385.html