字节对齐是在分配内存时需要考虑的问题,两个小算法:
假定目前该变量占用n个字节,对齐目标是align,求返回的占用实际内存大小。
(1)最容易想到的算法:
unsigned int calc_align(unsigned int n,unsigned align)
{
if ( n / align * align == n)
return n;
return (n / align + 1) * align;
}
就是判断一下,当前占用的内存字节,是否是alin的整数倍。如果是那么直接返回,这个占用字节数;如果不满足,那么直接加一个align来对齐。
n / align * align == n
只有当n是align的整数倍的时候,可以实现这个等于号。
(2)更好的算法
unsigned int calc_align(unsigned int n,unsigned align)
{
if ( n / align * align == n)
return n;
return (n / align + 1) * align;
}
对于更好的算法原理如下:
2字节对齐,要求地址位为2,4,6,8…,要求二进制位最后一位为0(2的1次方)
4字节对齐,要求地址位为4,8,12,16…,要求二进制位最后两位为0(2的2次方)
8字节对齐,要求地址位为8,16,24,32…,要求二进制位最后三位为0(2的3次方)
16字节对齐,要求地址位为16,32,48,64…,要求二进制位最后四位为0(2的4次方)
…
由此可见,我们只要对数据补齐对齐所需最少数据,然后将补齐位置0就可以实现对齐计算。
(1)(align-1),表示对齐所需的对齐位,如:2字节对齐为1,4字节为11,8字节为111,16字节为1111…
(2)(x+(align-1)),表示x补齐对齐所需数据
(3)&~(align-1),表示去除由于补齐造成的多余数据
(4) (x+(align-1))&~(align-1),表示对齐后的数据
举个例子:如8字节对齐。目前最小占用6个字节。
6 + (8 - 1)=0000 0110 + 0000 0111 = 0000 1101
0000 1101 & ~(0000 0111) = 0000 1000 //去除由于补齐造成的多余数据
数学证明该公式:
问:
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
说能够在某些系统中内存对齐.(估计是得到一个2 或者4的整数倍)
这个好象就是(x+3)&~3
这样就能满足对齐了吗?
请从数学上给说说.
谢谢
答(作者:win_hate):
对于两个正整数 x, n 总存在整数 q, r 使得
x = nq + r, 其中 0<= r <n //最小非负剩余
q, r 是唯一确定的。q = [x/n], r = x - n[x/n]. 这个是带余除法的一个简单形式。在 c 语言中, q, r 容易计算出来: q = x/n, r = x % n.
所谓把 x 按 n 对齐指的是:若 r=0, 取 qn, 若 r>0, 取 (q+1)n. 这也相当于把 x 表示为:
x = nq + r’, 其中 -n < r’ <=0 //最大非正剩余
nq 是我们所求。关键是如何用 c 语言计算它。由于我们能处理标准的带余除法,所以可以把这个式子转换成一个标准的带余除法,然后加以处理:
x+n = qn + (n+r’),其中 0<n+r’<=n //最大正剩余
x+n-1 = qn + (n+r’-1), 其中 0<= n+r’-1 <n //最小非负剩余
所以 qn = [(x+n-1)/n]n. 用 c 语言计算就是:
((x+n-1)/n)*n
若 n 是 2 的方幂, 比如 2^m,则除为右移 m 位,乘为左移 m 位。所以把 x+n-1 的最低 m 个二进制位清 0就可以了。得到:
(x+n-1) & (~(n-1))