结构体成员的内存分布与对齐

我们先看一道 IBM 和微软的笔试题:

IBM 笔试题:

struct{

short a1;

short a2;

short a3;

}A;

struct{

long a1;

short a2;

}B;

sizeof( A)=6, sizeof(B)=8, 为什么?

注: sizeof(short)=2,sizeof(long)=4

微软笔试题:

struct example1

{

       short a ;

       long b;

};

struct example2

{

char c;

example1 struct1;

short e;   

};

int main(int argc, char* argv[])

{

       example1 e1;

       example2 e2;

       int d=(unsigned int)&e2.struct1-(unsigned int)&e2.c;

       printf("%d,%d,%d/n",sizeof(e1),sizeof(e2),d);

       return 0;

}

输出结果?

要能清除的分析上面的问题就要搞清楚结构体变量的成员在内存里是如何分布的、成员先后顺序是怎样的、成员之间是连续的还是分散的、还是其他的什么形式?其实这些问题既和软件相关又和硬件相关。所谓软件相关主要是指和具体的编程语言的编译器的特性相关,编译器为了优化 CPU 访问内存的效率,在生成结构体成员的起始地址时遵循着某种特定的规则,这就是所谓的 结构体成员“对齐”; 所谓硬件相关主要是指 CPU 的“字节序”问题,也就是大于一个字节类型的数据如 int 类型、 short 类型等,在内存中的存放顺序,即单个字节与高低地址的对应关系。字节序分为两类: Big-Endian 和 Little-Endian ,有的文章上称之为“大端”和“小端”,他们是这样定义的:

Little-Endian 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端; Big-Endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

Intel 、VAX 和Unisys 处理器的计算机中的数据的字节顺序是 Little-Endian , IBM 大型机和大多数Unix 平台的计算机中字节顺序是 Big –Endian 。

关与 Big-Endian 和 Little-Endian 问题本文暂不做详细讨论,本文将以小端机(此处为 intel x86 架构的计算机)、 OS : WindowsXp 和 VC++6.0 编译器来详细讨论结构体成员的“对齐”问题。

前面说了 , 为了优化 CPU 访问内存的效率,程序语言的编译器在做变量的存储分配时就进行了分配优化处理,优化规则大致原则是这样 :

对于 n 字节的元素 (n=2,4,8,...) ,它的首地址能被 n 整除,这种原则称为“对齐 ”,如 WORD(2 字节 ) 的值应该能被 2 整除的位置, DWORD ( 4 字节)应该在能被 4 整除的位置。

对于结构体来说,结构体的成员在内存中顺序存放,所占内存地址依次增高,第一个成员处于低地址处,最后一个成员处于最高地址处,但结构体成员的内存分配不一定是连续的,编译器会对其成员变量依据前面介绍的 “对齐”原则进行处理。对待每个成员类似于对待单个 n 字节的元素一样,依次为每个元素找一个适合的首地址,使得其符合上述的“对齐”原则。通常编译器中可以设置一个对齐参数 n ,但这个 n 并不是结构体成员实际的对齐参数, VC++6.0 中结构体的每个成员实际对齐参数 N 通常是这样计算得到的 N = min(sizeof( 该成员类型 ) , n) ( n 为 VC++6.0 中可设置的值)。

成员的内存分配规律是这样的:从结构体的首地址开始向后依次为每个成员寻找第一个满足条件的首地址 x ,该条件是 x % N = 0 并且整个结构的长度必须为各个成员所使用的对齐参数中最大的那个值的最小整数倍 , 不够就补空字节

结构体中所有成员的对齐参数 N 的最大值称为结构体的对齐参数

VC++6.0 中 n 默认是 8 个字节,可以修改这个设定的对齐参数,方法为在菜单“工程”的“设置”中的“ C/C++ ”选项卡的“分类”中 Code Generation ”的“ Struct member alignment 中设置, 1byte 2byte 4byte 8byte 16byte 等几种,默认为 8byte

http://jisuanji.xawl.org/Data/Working/1EC27F05-1E24-4293-943E-E45DE41CF198.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值