C/C++里地址对齐理解

本文主要讲述一下C/C++里变量地址的对齐,不仅仅是C/C++,其它语言也是一样。这个是计算机系统要求的。


一 为什么要对齐

在硬件设计上,为了提高效率,CPU从RAM里拿数据不是一个字节一个字节去读的,而是一次读取多个字节,例如如8个。如果代码里的变量地址不对齐(不是8的倍数),那么就会降低CPU的效率。

例如一个长整型是8个字节,如果其起始地址不是8的倍数,如下图这样,绿色是长整型数据在ram里的排布,
在这里插入图片描述
那么CPU就需要取2次才能拿到这个长整型数据的完整值,第一次从位置0取8个字节,第二次从位置8取8个字节;如果其地址是8的倍数,那么就只需要取一次了。

我们在编写程序时,可能会有大量的变量,如果不对齐,叠加起来就会大幅降低CPU的效率。


二 如何保证对齐

编译器在把源码变成汇编代码时,会在代码中放入命令来指示需要的对齐字节数,如下这种,

.align 4

这是一个对齐伪指令,表示要求4字节对齐,也可以改成2,8,16等。这条指令后面的内存变量必须从下一个能被4整除的地址开始分配。如果下一个地址不能被4整除,汇编程序将空出若干个字节,直到下一个地址能被4整除为止。

这样保证了第一个变量的起始地址是按要求对齐的,那么后续的其它变量只要按照一定的对齐策略,那么整体cpu效率就会得到提高。


三 结构体对齐

假设要求是4字节对齐,对齐策略是:

  • 对于第一个元素,不用关心其对齐,直接放在起始地址位。
  • 对于后面每一个元素,将该元素长度和要求的对齐字节数进行比较,按照小一点的那个数字进行对齐。
  • 根据上一个策略,每个元素都有一个实际对齐字节数,这样会有一个最大实际对齐字节数,结构体的整体大小是这个最大值的整数倍。

例子1

假设struct A定义如下,

struct A
{
    int d1;
    char d2;
    int d3;
};

那么就会按照如下方式排布,白色部分为编译器插入的3字节间隙
在这里插入图片描述
背后原理:

  1. d1,长度为4,直接放置
  2. d2,长度为1,对齐字节数是4,所以按照1字节对齐,那么d2就放在位置4处
  3. d3,长度为4,对齐字节数是4,两者相等就按照4对齐,位置4后面满足4对齐的只有位置8了(5,6,7都不能被4整除),所以d3的起始地址在位置8

这样这个结构体的实际长度是12个字节(4的3倍,4是实际最大对齐字节数),d2后面会多出3个padding字节,这是通过牺牲一定的空间来实现对齐,提高效率。

例子2

假设结构体的定义如下,char型元素放在最后,

struct A
{
    int d1;
    int d2;
    char d3;
};

那么d3后面还需要补充3个padding字节吗?因为d3的起始地址已经是4字节对齐的。答案是需要,因为对齐策略要求结构体整体大小是最大实际对齐数的整数倍。

所以这个结构体内存分布如下,仍然占12个字节(4的3倍,4是实际最大对齐字节数),白色部分为编译器插入的3字节间隙
在这里插入图片描述

例子3

假设结构体的定义如下,

struct A
{
    int d1;
    char d2;
    char d3;
    int d4;
};

其分布如下,白色部分为编译器插入的2字节间隙
在这里插入图片描述
按照之前说的对齐策略,分析如下,

  1. d1,长度为4,直接放置
  2. d2,长度为1,对齐字节数是4,两者相等就按照1对齐,d2放置在位置4
  3. d3,长度为1,对齐字节数是4,两者相等就按照4对齐,d2放置在位置5
  4. d4,长度为4,对齐字节数是4,两者相等就按照4对齐,位置5后面满足4对齐的只有位置8了,所以d4的起始地址在位置8

同理,如果结构体定义如下,

struct A
{
    int d1;
    char d2;
    short d3;
    int d4;
};

那么其分布如下,白色部分为编译器插入的1字节间隙
在这里插入图片描述

例子4

假设结构体的定义如下,

struct A
{
	char d1;
	char d2;
	char d3;
};

这个结构体的有效字节数是3,那么定义一个结构体数组,

struct A aa[3];

那么这个数组是如何分布的呢?如下,
在这里插入图片描述

分析:

  • 整体大小也是3字节,无需插入间隙

可以看出如果这种排布的结构体,会降低CPU效率(读取第2个元素需要读取2次),所以一般会补充一个间隙,如下,

struct A
{
	char d1;
	char d2;
	char d3;
	char padding;
};

小结

这里再来聊一下这个结构体内部元素的对齐策略,为什么实际对齐字节数是自身大小和要求对齐字节数2者的较小者?
这里以char类型举例,1字节小于要求的4字节对齐,那么这个元素肯定一次就可以读取完,如果后面的也还是char,那么把这2个元素在内存上挨在一起,然后也可以一次读完,依然提高了效率;如果一个元素后面填上3字节间隙,那么这2个元素就要占8个字节,而且还要读取2次,既浪费空间也浪费时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值