内存对齐

  • memcpy的错误示范

    今天在使用memcpy时突发奇想,以前用这个拷贝int,char等类型指针都可以实现,那可不可以实现将char类型指针数据拷贝到结构体/类中呢?

    比如定义一个结构体:

struct Test
{	
    char c1;
    int i1;
    char c2;
}test;

    再定义一个char类型指针,由于Test结构体中有2个char类型(2*1个字节),1个int类型(4个字节),所以开辟6个字节的内存空间:

char *c = (char*)malloc(6);

    再给char指针指向的内存赋值,我将char指针首地址至首地址+5所指向的内存空间赋值:

*c = 1;
*(c+1) = 2;
*(c+2) = 3;
*(c+3) = 4;
*(c+4) = 5;
*(c+5) = 6;

    再通过memcpy拷贝一下内存:

memcpy(&test,c,6);

     原本想着是test.c1 = *c = 1,test.i1 = *(c+1)<<24+*(c+2)<<16+*(c+3)<<8+*(c+4) = 33752069,test.c2 = *(c+5) = 6。可是最后结果悲剧了,以下是运行结果:


   这是什么原因导致的呢?下面开始讲解今日的收获——内存对齐。

  • 内存对齐

    有良好编程习惯的小伙伴都会使用sizeof(类型)来获得类型的内存大小,我们先来看一下test的内存长度,没错,是12!与我们之前想的6个字节有着很大的差距。

  

    原来编译器在分配内存是并不是单纯的"你定义一个类型,内存地址往上加一个类型长度单位",而是存在一个内存对齐的概念。下图中test.c1地址为0x3af688,test.i1地址为0x3af68c,test.c2的地址为0x3af690。c1和i1的地址空间跨越了4个字节,i1和c2跨越了4个字节。

    可以这么理解,假设4个字节单位是一个房间,而类型是一个人,char是一个瘦子,int是一个大胖子。这个大胖子太胖了,自己住一个房间,别人根本挤不进去。而有的同学就在想了,那两个瘦子(char)可以住一个房间么?伴随着这个想法,我们改一下结构体的定义,再运行看下分配内存地址:

struct Test
{
    char c1;
    char c2;
    int i1;
}test;

    c2紧跟c1,而i1离c2有3个字节的距离。也就是说c1和c2安排在了一个房间,i1被安排在了另一个房间。再来看一下test的内存长度,变成了8,也就少开了一间房:

    原来编译器在分配内存的时候,按照定义顺序分配内存地址(房间)。先定义先分配,后定义后分配。编译器会先看该类型能不能住的下当前房间,住得下往里塞,住不下开另一个房间。一般房间有4张床,而数据类型大小为1,2,4,8(x64)个字节,除了8个字节的“超级大胖子”,需要凿开一面墙,为他开两个房间,睡8张床之外,其它类型数据最多只需要住1个房间。

    值得一提的是,房间首地址都能被4整除,short等2个字节长度的类型所开辟的内存首地址能被2整除。也就是说在char类型后面紧接着定义一个short,它的床不一定紧挨这char,而是看当前床地址是双数还是单数,双数给short住,单数不给住。若当前房间没有双数的床,那么就移至下一个房间,住双数编号的床。

    以上就是所谓的内存对齐的内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值