结构体的内存分配,我个人是觉得比较蛋疼的,它有一个需要遵循的原则,地址对齐,也有人称为内存对齐,叫法没关系,反正我只是“拿来”,会用就行。
好了,先有这么一个概念,什么是内存对齐,先丢一边。……~(~o ̄▽ ̄)~o 。。。滚来滚去……o~(_△_o~) ~。。
设char占用1个字节,int占用4个字节。
那么问题1
struct A
{
char a;
int a0;
}ma;
char a1;
a1 = sizeof(ma);
?_?,为什么是8???,不是5?
是的,不是5,在编译器里面,为了非连续变量取得的地址能整除于结构体的基地址(结构体的分配的基地址也需要满足可以整除于所占用的内存的最大数据类型的字节数,这句话好绕啊_(:3」∠)_),偏移地址需要对齐。就是说在给变量分配的时候,如果不是连续定义的变量,直接分配一个最大的内存空间,即使我给a0变量定义的是一个char型变量,编译器依旧给其分配了4个字节。
关于偏移地址对齐的说法,我个人倾向于同意的说法是,在给结构体分配内存空间时,如果变量地址不连续(注意这句话,很重要),编译器宁可取结构体中内存占用最大的元素为每个变量分配内存,不够的空间予以补足,只是调用的时候不用而已。
下面结合*.map文件分析一下各个变量的内存分配
ma 0x2000002c Data 8 main.o(.data)
a2 0x20000034 Data 1 main.o(.data)
a3 0x20000035 Data 1 main.o(.data)
a4 0x20000036 Data 1 main.o(.data)
a5 0x20000038 Data 4 main.o(.data)
上面是各个变量的地址分配,我没有在*. map文件中找到 ma.a0 和 ma.a1 的变量地址,(~ ̄▽ ̄~) 那又怎样,不就绕个弯嘛。
<( ̄ c ̄)y▂ξ,现在可以分析了。
在上图中我通过一个指针变量将ma.a1的地址取了出来,然后执行到红点处停止,结合*.map文件分析,a2地址为0x20000034,ma地址为0x2000002c ,两者相减为8,就是ma的内存分配大小,然后我之前说过,结构体中变量的内存的分配是直接每个变量分配一个所有元素中最大的内存占用元素的,也就是说ma .a0也占用了4个字节。
现在,验证方法就是用ma.a1的地址减去ma的地址。
即 0x20000030 - 0x2000002c = 4;
结果出来了,a0变量占用了4个字节的内存,还有两个字节的内存空间去哪里了?直接屏蔽了呗。
|