现在的位置: 首页 > 综合 > 正文

数据结构内存边界对齐的三条原则

2014年07月18日 ⁄ 综合 ⁄ 共 2200字 ⁄ 字号 评论关闭

struct example1 {
    short a;
    long b;
};

struct example2 {
    char c;
    struct example1 e;
    short s;
};
#pragma  pack()
在 原来那篇日志中,通过写程序测试发现规律后,便推测上述的strurct example2的结构大小应该是24个字节,但YGone网友在vs2008上得到的结果是16个字节,自己这才写程序在vc6.0, vs2008, gcc上测试,得到的结果都是16个字节。
struct example2数据结构的大小是16个字节,这个值是这样计算出来的:
1(char c) + 3(padding) + 8(struct example1 e) + 2(short s) + 2(padding) = 16。
struct example1的大小是8字节,这个非常明显。

为什么struct example2的大小要如此计算呢?通过学习,总结出数据结构内存边界对齐的三条原则,如下:
原 则一:内存边界对齐是为了简化CPU和内存之间的接口设计,提高内存读写的效率。每一种原子数据在存储时都有两个属性:它的起始地址约束和它本身的大小。 在windows下,可以使用__alignof(type)来查看type类型的起始地址约束,char是1,short是2,int是4, double是8等等。在linux下,char是1,short是2,其他都是4。
原则二:对于非原子类型的组合类型,比如struct, union, class等,它的起始地址约束必须能够满足它的所有数据成员的起始地址约束。即,整体必须照顾到每一个组成部分。
原则三:对于一个组合类型S,分配一个S类型的数组,则S中每个S对象都必须满足S的起始地址约束。原则三的结果是,一个组合类型,很有可能为了满足它自身的起始地址约束而在它的后面填充一些字节。

现在来看为什么struct example2的大小应该那样计算:
sizeof(struct example2) = sizeof(char) + padding_c_e + sizeof(struct example1) + padding_e_s + sizeof(short) + padding_end
先要计算struct example1的大小:
sizeof(struct example1) = sizeof(short) + padding_a_b + sizeof(long) + padding_end
alignof(short) = 2, alignof(long) = 4,所以short a之后必须填充两个字节才能保证long b的起始地址是4的整数倍,所以padding_a_b = 2。
那 么alignof(struct example1)是多少呢?根据原则二,alignof(struct example1)必须满足成员a和b的对齐约束。假设struct example1对象的起始地址是x,x必须是2的整数倍以保证成员a能对齐,同时x+offset(b) = x+4必须是4的整数倍以保证成员b能对齐,要使x+4是4的整数倍,x也必须是4的整数倍,所以align(struct example1) = 4。现在:
sizeof(struct example1) = 2 + 2 + 4 + padding_end = 8 + padding_end,因为alignof(struct example1) = 4,所以末尾不需要填充,因此:
sizeof(struct example1) = 2 + 2 + 4 = 8。
现在计算struct example2的大小:
sizeof(struct example2) = sizeof(char) + padding_c_e + sizeof(struct example1) + padding_e_s + sizeof(short) + padding_end
= 1 + padding_c_e  + 8 + padding_e_s + 2 + padding_end
因为alignof(struct example1) = 4,所以padding_c_e = 3,这样1+3为4的整数倍。
因为alignof(short) = 2,而1+3+8就是2的整数倍,所以padding_e_s = 0
根据计算alignof(struct example1)的过程,可以计算出alignof(struct example2) = 4,而1 + 3 + 8 + 2 = 14,不是4的整数倍,所以padding_end = 2。
最终:
sizeof(struct example2) = 1 + 3 + 8 + 0 + 2 + 2 = 16

如果使用的#pragma pack(2)结果又怎么样呢?
此 时,在struct example1中,alignof(long)=4,但是因为#pragma pack(2),所以long b的偏移量不需要填充就能满足2字节对齐的要求,所以sizeof(struct example1) = 2 + 4 = 6, alignof(struct example1) = 2
所以
sizeof(struct example2) = sizeof(char)  + padding_c_e + sizeof(struct example1) + padding_e_s + sizeof(short) + padding_end
= 1 + 1 + 6 + 0 + 2 + 0 = 10

 

 

http://blog.csdn.net/jcwKyl/archive/2010/03/08/5356294.aspx

抱歉!评论已关闭.