我想你一定看到过类似这样的代码
((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1))
看字大致意思是要内存对齐,但也不明白为为什么写成这样?
在计算机中主存按一个传送单位(32/64/128位)进行存取,按字节编址
如果传送单位为32位,也就意味着第0-3字节能同时读写,第4-7字节能同时读写。
如果需要读写3-6字节的数据,则计算机需要分别读两次(0-3 4-7),无法直接读取3-6字节的数据
总而言之,对齐的粒度一定是2的n次方这种形式,在二进制表示下一定会长成这样(1后面跟着n个0):
000100...00
假设我们要分配的变量需要size
大小的空间。
要想数据不出现横跨两个传送单位的尴尬情况,我们必须按照传送单位的整数倍去分配内存。
size & ~(ALIGNMENT - 1)
这里的ALIGNMENT
根据自己的需求和硬件平台变动
现在先假定有声明
#define ALIGNMENT 4 // 4字节对齐
(ALIGNMENT - 1)
这一块为0011
,取反之后为1100
,相当于掩码,最后两位会被置为0。这样就得出来的数一定是ALIGNMENT
(本例中是4)的整数倍
现在我们已经知道了~(ALIGNMENT-1)
是为了取整
请你算一下如果size=3
按照size & ~(ALIGNMENT - 1)
来算的话内存怎么分配
0011 & 1100 = 0
这显然是错的,所以我们得加上 ALIGNMENT - 1
来确保当size<ALIGNMENT
时也能得到正确结果。
为什么不是加上ALIGNMENT
呢?
-
~(ALIGNMENT - 1)
是把低n位清零,我们将低n位先填满这样当size>0
时会进行向上取整 -
如果是加ALIGNMENT,当
size=ALIGNMENT
时我们会多申请一个内存单元
所以最后的表达式为:
((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1))
size | size & ~(ALIGNMENT - 1) | ((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1)) |
---|---|---|
0 | 0 | 0 |
3 | 0(错误) | 4 |
4 | 8(多分配了不必要的内存) | 4 |