- 论坛徽章:
- 0
|
最近刚好搞了个内存对齐的东东,将经验拿来大家共享,不足之处请不吝砸砖
首先我们要明白一件事情,任何变量在内存中都有地址,而处理器是有位数的,例如32位,64位,意思就是说处理器一次处理32bit(4bytes)或者64bit(8bytes)。下面以32位为例:
对于0开始的2个bytes,可以一次取出来,但是对于3开始的2个B,就要两次才能取出来,因为0-3取一次,4-7取第二次,所以需要两次。为了提高效率,我们希望将这两个字节放在能一次取出来的地方,就是4-5这两个B上。所以,内存对齐就是尽量将变量的首地址放在能一次取出的地址上。这也就是我们的结构体长度往往超过所有变量长度的和的原因。其实你申明如下变量(顺序有关)
struct{
char a;
int b;
short c;
long d;
};
再分别将他们的地址打印出来看看,不是连续分配的,内存对齐很神奇吧。
那么我们怎么判断变量首地址被分配到哪里去了呢?(内存对齐是怎么实现的)
其实很简单,你必须明白以下规则
1.系统对齐长度LO:32位机默认为4字节,程序中可以用#pragma pack(2)将其改为2,只能是2^n,不能大于4。大了不起作用。
2.你的变量长度LV,基本变量,包括(singed/unsigned)char, short,int,long,float,double,字符串变量不会对内存对齐产生影响。
3.当前可用地址之后第一个能整除MIN(LO,LV)的地址就是内存对齐之后的地址。
另外,内存对齐是编译器相关的,不同的编译器可能有细微的差别,但总体遵循以上原则。
这是我的函数
/*************************************
* 根据当前地址和数据类型判断是否需要对齐
* 如果需要对齐,返回下一个变量可用地址
* p 内存当前地址
* len 需对齐的变量长度, 只能是简单变量
* 例如 char 1
* short 2
* int 4
* long 4
* float 4
* double 8
* 返回值,对齐后的地址
*************************************/
void * getMemAddr( void * p, unsigned short len )
{
len = MIN( len, PACK_LEN );
if( p == NULL ) return NULL;
if( (unsigned int)p%len != 0 )
{
return p+len-(unsigned int)p%len;
}
else
return p;
}
|
PACK_LEN就是LO,此处定义为4,32位机的
[ 本帖最后由 blackuhlan 于 2008-7-18 07:11 编辑 ] |
|