今天看实战书时看到结构体部分时,有些内存分配方面的问题就查了下资料,就内存对齐做点笔记吧!
平台移植和提高性能时就需要内存对齐了;
不同的编辑器都有自己默认的对齐系数也可以称做对齐模数;可以用#pragma pack(number);对对齐系数进行修改,number = 1, 2, 4, 8, 16
内存对齐规则:
1.数据成员对齐规则:结构体(或共用体)的数据成员的第一个成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中比较小的的那个进行。
2.结构体(或共用体)的整体对齐规则:在数据成员完成各自的对齐之后,结构体(或共用体)自身也要进行对齐,对齐按照#pragma pack指定的数值和结构体(或联合体)中最大的数据成员的长度中比较小的那个进行。
eg:
#pragma pack(2)
struct test_t
{
int a; /* int型长度4 > 2 按2对齐;起始offset=0 0%2=0;存放位置区间[0,3] */
char b; /* char型长度1 < 2 按1对齐;起始offset=4 4%2=0;存放位置区间[4] */
short c; /* short型长度2 = 2 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7]
这里可能读者会有些疑问为什么offset不是5,原因是每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节当offset=5时 5%2不为0,所以offset++ */
char d[6]; /* char型长度1 < 2 按1对齐;起始offset=8 8%2=0;存放位置区间[8,C] */
};
成员总大小=14;
整体对齐系数=min(max(int,short,char), 2) = 2
整体大小(size)=14
微软C编译器的对齐策略有:
1.结构体(或共用体)的首地址offset是其成员变量中最长成员的整数倍,即在开辟结构体(或共用体)空间时先找到成员中长度最大的数据类型,然后在地址中寻找是该数据类型整数倍的地址作为结构体的首地址,长度最大的数据类型的长度作为对齐系数;
2.结构体(或共用体)的一个成员开辟空间之前,先检查要开辟空间的首地址相对于结构体首地址的偏移是不是该成员的整数倍,如果是的话,就存放该成员不时的话,就在该成员和上一个成员之间填充一定的字节,直至时期符合整数倍的要求;
3. 结构体的总大小为结构体对齐系数的整数倍,这样就有可能会在最末一个成员之后添加填充字节
若根据这些对齐策略则上面例题应为:
eg:
#pragma pack(2)
struct test_t
{
int a; /* int型长度4 > 2 按2对齐;起始offset=0 0%2=0;存放位置区间[0,3] */
char b; /* char型长度1 < 2 按1对齐;起始offset=4 4%2=0;存放位置区间[4] */
short c; /* short型长度2 = 2 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7]*/
char d[6]; /* char型长度1 < 2 按1对齐;起始offset=8 8%2=0;存放位置区间[8,C] */
};
成员总大小=14;
整体对齐系数=max(int,char,short) = 4
整体大小(size)=14 + 2 = 16 /*14%4=2*/
阅读(429) | 评论(0) | 转发(0) |