c语言内存对齐与#pragma pack(n)

一、什么是内存对齐,为什么要内存对齐 

    • 现在计算机内存空间都是按照byte字节划分的,理论上讲对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址上访问,这就需要各种数据类型按照一定的规则在空间上排列,而不是一个接一个的排放,这就是内存对齐。
    • cpu对内存的读取不是连续的而是分块读取的,块的大小只能是2i个字节数,从cpu的读取性能和效率来考虑,若读取的数据未对齐,则需要两次总线周期来访问内存,因而效率会大打折扣
    • 另外某些固定的硬件平台只能从规定的相对地址处读取特定类型的数据,否则会产生硬件异常。
    • 如果不按照适合平台要求对数据存放进行对齐,会存在效率上的损失。比如有些平台每次读都是从偶地址开始,如果一个int型(32位系统)存放在偶地址开始的地方,那么一个周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要两个读周期,并对两次读出结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。

二、内存对齐规则

  • 在不用#pagrama pack()包裹的情况下,结构体或联合体按照编译器默认的对齐方式有以下三个对其原则:
    • 数据成员对齐原则:结构(struct或union)的数据成员,第一个数据成员存放在offset为0的地方,以后每个数据成员存储的起始位置都要从该成员占用内存大小的整数倍开始
    • 结构体作为成员的原则:如果一个结构中有某些结构体成员,则结构的成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始)
    • 结构(或联合)的整体对齐原则:在数据成员各自对齐后,结构(或联合)本身也要进行对齐,即以结构体内部占用内存空间最大的数据类型进行对齐。(等同于sizeof该结构体的结果必须是其内部最大成员占用内存的整数倍)
      • 1 struct mystruct
        2 {
        3 char a;//偏移量为0;a占用一个字节
        4 double b;//下一个可用地址偏移量为1,不是sizeof(double)=8的整数倍,需要补7个字节
        5 int c;//下一个可用地址偏移量为1+7+8=16,是sizeof(int)=4的整数倍,满足Int的对齐方式
        6 }//所有成员变量都分配了空间,空间大小=1+7+8+4=20,不是最大空间类型double的整数倍,所以需要填充4个字节以满足结构体大小为sizeof(double)=8的整数倍
        7 sizeof(mystruct)=24;
      • 对于结构体整体对齐:

      •              

 三、#pragma pack()自定义数据对齐规则

  • #pragma pack(n):每个特定平台上的编译器都有自己默认的对齐系数,程序员可以通过预编译指令#pragma pack(n),n=1,2,4,8,16来改变这一系数
    • 数据成员对齐规则:结构或联合的数据成员,第一个数据成员在offset为0的地方,以后每个数据成员的对齐方式都按照#pragma pack指定的数值这个数据成员自身占用内存中比较小的那个进行。
    • 结构或联合整体对其原则:在数据成员完成自身对齐后,结构或联合本身也要进行对齐,对齐按照#pragma pack(n)指定的数值和结构或联合最大数据成员占用内存中比较小的那个进行。

猜你喜欢

转载自www.cnblogs.com/southcyy/p/10175163.html
今日推荐