内存对齐

问题:

   在一本书上看到了内存对齐,脑袋突然转不过来,看了作者解释了一大通,还是没能体会到,无奈~~~

解决:

   当然是寻找广大网友,看了网友的解释,我才理解了作者文字中的意思,但是对于刚看到这句话时候的我,真的反应不过来。

引用:(以下是引用别人对于内存规则的讲解,个人觉得较好理解)

    1.对于结构的各个成员,第一个成员位于偏移为0的位置,以后的每个数据成员的偏移量必须是  min(#pragma pack()指定的数,这个数据成员的自身长度)的倍数

     2.在所有的数据成员完成各自对齐之后,结构或联合体本身也要进行对齐,对齐将按照 #pragram pack 指定的数值和结构或者联合体最大数据成员长度中比较小的那个  也就是  min(#pragram pack() , 长度最长的数据成员);

   #pragram pack(n)  表示的是设置n字节对齐,vc6默认的是8,这个是重点,不然接下来没法比较

举个栗子

    struct Test{

       char c1;

       short s;

       char c2;

       int i;

};

        如果我说他的大小为(1+2+1+4=8),你信吗?当然,如果这样我就不会纠结作者写的东西了。先根据第一条内存对齐规则,第一个变量c1相对偏移地址为0,第二个变量为short型,按照规则min(8,2)=2,所以偏移量为2的倍数,即要在第一个变量后补一个字节,第二个变量的起始地址为2,接下来又是一个char型,min(8,1)=1,刚好第三个变量在地址4,为1的倍数,不用进行补字节操作,第四个为int型,min(8,4)=4,所以偏移量应该为4的倍数,所以需要在第三个变量补三个字节。

       然后再根据第二条规则,寻找结构体中最大成员长度的变量与指定数值长度进行比较,找出较小的那个,即min(8,int)=(8,4)=4;所以结构体的大小应该为4的倍数,这里刚刚好,所以不用补齐字节

        最后的结果是0x|00|0xxx|0000 (x表示补的字节数)所以最后的结果为12,也许有人跟我有一样的疑问,倍数为什么都是从最小的开始算,其实再想一下,计算机的内存有限,本来这种内存对齐方式就是一种空间换时间的方式,牺牲了内存来取得访问时间的减少,如果往大倍数加,那还不如不对齐,也没必要,每个变量占的空间本来就那么多,再给它多开辟几个空间,它依然只占用那么一点空间。

避免内存对齐的影响

一个简单的方法是重新排布结构体中的变量,还是上面那个结构体

    struct Test{

       char c1;

       char c2;

short s;

       int i;

};

这样,每个成员都对齐在其自然边界上,从而避免了编译器自动补齐,这是技巧之一,除此还可以使用#pragma pack()来改变编译器的默认对齐规则

使用指令#pragma pack(n),编译器将按照n个字节对齐

该指令还有一个条件,虽然指定了按照n个字节对齐,但是并不是每个成员都按照那个字节对齐,每个成员是按自己的方式进行对齐。

对齐规则:

       每个成员按其类型的对齐参数(通常是这个类型的大小)和指定的对齐参数(这里是n字节)中较小的一个对齐,即min(n,sizeof(item)).并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。

使用指令#pragma pack(),编译器将取消自定义字节对齐方式

再来一个栗子

#pragma pack(8)

struct Test0{

       char c1;

        int i;

};

struct Test1{

       char c2;

       Test0 d;

        int k;

};

#pragma pack()

先对Test0分析

      Test0中char型变量为1个字节,按照对齐规则,选取min(1,8)=1,所以c按1字节对齐,int型为4个字节,min(8,4)=4,按4字节对齐,所以char型,即变量c后应该补三个字节.最终整个大小为8个字节,刚好是8的倍数(对齐后的长度是成员中最大的对齐参数的整数倍),不用进行字节补齐,0xxx|0000,占8个字节

Test1

分析Test1前要先了解结构体型变量在结构体中的对齐规则:

       对于结构体来说,他的默认对齐方式就是它的所有成员使用的对齐参数最大的一个,很明显在Test0中最大的就是int型,占4个字节,以它作用结构体的自然边界,所以现在是这种情况  0xxx|0xxx|0000 ,第一个竖线前的四个字节是Test1中c2占用字节,因为Test0结构体中的c1按照4字节对齐,所以c1应该地址4的地方,c2后面就应该补3三个字节,同样道理,c1后也应该补三个字节,使Test0中i变量地址为4的倍数(基于对齐规则,如果看不懂,建议再看一下前面的对齐规则),所以i变量在地址8处,为4的倍数,此时占用了12个字节。所以变量k刚好在其自然边界上,不用再进行字节补齐。所以最终结果为16个字节    0xxx|0xxx|0000|0000

总结

对于结构体,编译器会自动进行成员变量的对齐,
以提高运算效率。缺省情况下,编译器为结构体的每个成员按其自然对界(natural alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。  
自然对界(natural alignment)即默认对齐方式,是指按结构体的成员中 size 最大的成员对齐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值