结构体和位域对齐的原则(3/5原则)

C语言结构体对齐问题详解

测试环境32位机 WinXP:

编译器VC6(MS cl.exe ) 和 mingw32-gcc-4.5.2

 

1 结构体数据对齐(没有#pragma pack()宏定义)

结构体对齐可以总结为三个基本原则

数据成员对齐规则:

结构体的数据成员中,第一个成员从offset为0的地址开始,以后每一个成员存储的起始位置为该成员大小的整数倍(在win32中int为32bit也即4字节对齐)

结构体作为成员:

如果一个结构体1作为另一个结构体2的数据成员,则在结构体2中结构体1要从1内部成员最大的整数倍地址开始存储。

结构体的总大小(sizeof):

为该结构体内部最大基本类型的整数倍,不足的要补齐,而不是简单的所有成员的大小总和。

举例说明

struct{

C语言结构体对齐问题详解

测试环境32位机 WinXP:

编译器VC6(MS cl.exe ) 和 mingw32-gcc-4.5.2

 

1 结构体数据对齐(没有#pragma pack()宏定义)

结构体对齐可以总结为三个基本原则

数据成员对齐规则:

结构体的数据成员中,第一个成员从offset为0的地址开始,以后每一个成员存储的起始位置为该成员大小的整数倍(在win32中int为32bit也即4字节对齐)

结构体作为成员:

如果一个结构体1作为另一个结构体2的数据成员,则在结构体2中结构体1要从1内部成员最大的整数倍地址开始存储。

结构体的总大小(sizeof):

为该结构体内部最大基本类型的整数倍,不足的要补齐,而不是简单的所有成员的大小总和。

举例说明

struct{

short a;

short b;

short c; }A; sizeof(A) = 6;(vc6与gcc相同)

struct{

long a;

short c; }A; sizeof(A) = 8;(vc6与gcc相同),根据原则③

它的内存分配为: a1 a2 a3 a4 , c1 c2 x x(a1为a的第一个字节,x为补齐字节,下同)

struct{

int a;

char b;

short c; }A;

sizeof(A) = 8;

A的内存分配为: a1 a2 a3 a4, b1 x c1 c2(原则1)

struct{

char a;

int b;

short c; }A1;

sizeof(A1) = 12; (vc6与gcc相同)

A1的内存分配为: a1 x x x, b1 b2 b3 b4, c1 c2 x x

下面是更复杂的情况,结构体作为成员

struct{

int a;

doubl b;

short c; }A; // sizeof(A) = 24 (vc6与gcc相同)

struct{

    char a,b;

int c;

double d;

short e;

struct A h;

}B;

sizeof(B) = 48 //(vc6与gcc相同)

A的内存分布: a1 a2 a3 a4 x x x x, b1 b2 b3 b4 b5 b6 b7 b7, c1 c2 x x x x x x

B的内存分布:a1 b1 x x, c1 c2 c3 c4 , d1 d2 d3 d4 d5 d6 d7 d8, e1 e2 x x x x, A的分布

 

 

2 加入#pragma pack()宏定义)

#pragma pack(1)

上面的AB大小分别为14,30,对应于AB的内存分布,去掉x。

pack(2)时为14,30

pack(4)时为16,36

 

3 结构体的位域

结构体中引入位于是为了压缩存储空间。而且位于成员不能单独计算sizeof。

位域大致有5条基本规则。

① 如果相邻字段的类型相同,且位宽之和小于该类型的sizeof(), 则可以紧邻着前一个字段存储,直到不能在容纳位置;

struct{

char a:2;

char b:4;

char c:5; }A; // sizeof(A) = 2

内存分布: a1 a2 x x, b1 b2 b3 b4, c1 c2 c3 c4 c5 x x x,这里每一个代表一个bit,与上一节不同

struct{

int a:2;

int b:3;

int c:3; }A; // sizeof(A) = 4, 参照后面的原则5

 

②如果相邻字段的类型相同,但是位宽之和大于该类型的sizeof(), 则后面的字段将从新的存储单元开始存储,且offset为其类型大小的整数倍;

struct{

char a:6;

char b:3;

char c:3; }A; // sizeof(A) = 2

struct{

int a:20;

int b:20;

int c:3; }A; // sizeof(A) = 8, 同时参照后面的原则5

 

③如果相邻位域字段类型不同,各编译器的处理不同,VC6不压缩,GCC压缩。

struct{

int a:4;

char b:1;

int c:3; }A;

sizeof(A) = 12, VC6

sizeof(A) = 4, gcc, 压缩了为什么不是3? 同时参照后面的原则5

 

④如果位域字段之间插入非位域字段,各编译器的处理不同

struct{

int a:4;

char b;

int c:3; }A;

sizeof(A) = 12, VC6

sizeof(A) = 4, gcc, a1 a2 a3 a4 x x x x ,b1~b8, c1 c2 c3 x x x x x

 

struct{

char a:4;

char b;

char c:3; }A;

sizeof(A) = 3, VC6

sizeof(A) = 3, gcc,

 

⑤整个结构体的总大小为其最宽基本类型的整数倍。

short a;

short b;

short c; }A; sizeof(A) = 6;(vc6与gcc相同)

struct{

long a;

short c; }A; sizeof(A) = 8;(vc6与gcc相同),根据原则③

它的内存分配为: a1 a2 a3 a4 , c1 c2 x x(a1为a的第一个字节,x为补齐字节,下同)

struct{

int a;

char b;

short c; }A;

sizeof(A) = 8;

A的内存分配为: a1 a2 a3 a4, b1 x c1 c2(原则1)

struct{

char a;

int b;

short c; }A1;

sizeof(A1) = 12; (vc6与gcc相同)

A1的内存分配为: a1 x x x, b1 b2 b3 b4, c1 c2 x x

下面是更复杂的情况,结构体作为成员

struct{

int a;

doubl b;

short c; }A; // sizeof(A) = 24 (vc6与gcc相同)

struct{

    char a,b;

int c;

double d;

short e;

struct A h;

}B;

sizeof(B) = 48 //(vc6与gcc相同)

A的内存分布: a1 a2 a3 a4 x x x x, b1 b2 b3 b4 b5 b6 b7 b7, c1 c2 x x x x x x

B的内存分布:a1 b1 x x, c1 c2 c3 c4 , d1 d2 d3 d4 d5 d6 d7 d8, e1 e2 x x x x, A的分布

 

 

2 加入#pragma pack()宏定义)

#pragma pack(1)

上面的AB大小分别为14,30,对应于AB的内存分布,去掉x。

pack(2)时为14,30

pack(4)时为16,36

 

3 结构体的位域

结构体中引入位于是为了压缩存储空间。而且位于成员不能单独计算sizeof。

位域大致有5条基本规则。

① 如果相邻字段的类型相同,且位宽之和小于该类型的sizeof(), 则可以紧邻着前一个字段存储,直到不能在容纳位置;

struct{

char a:2;

char b:4;

char c:5; }A; // sizeof(A) = 2

内存分布: a1 a2 x x, b1 b2 b3 b4, c1 c2 c3 c4 c5 x x x,这里每一个代表一个bit,与上一节不同

struct{

int a:2;

int b:3;

int c:3; }A; // sizeof(A) = 4, 参照后面的原则5

 

②如果相邻字段的类型相同,但是位宽之和大于该类型的sizeof(), 则后面的字段将从新的存储单元开始存储,且offset为其类型大小的整数倍;

struct{

char a:6;

char b:3;

char c:3; }A; // sizeof(A) = 2

struct{

int a:20;

int b:20;

int c:3; }A; // sizeof(A) = 8, 同时参照后面的原则5

 

③如果相邻位域字段类型不同,各编译器的处理不同,VC6不压缩,GCC压缩。

struct{

int a:4;

char b:1;

int c:3; }A;

sizeof(A) = 12, VC6

sizeof(A) = 4, gcc, 压缩了为什么不是3? 同时参照后面的原则5

 

④如果位域字段之间插入非位域字段,各编译器的处理不同

struct{

int a:4;

char b;

int c:3; }A;

sizeof(A) = 12, VC6

sizeof(A) = 4, gcc, a1 a2 a3 a4 x x x x ,b1~b8, c1 c2 c3 x x x x x

 

struct{

char a:4;

char b;

char c:3; }A;

sizeof(A) = 3, VC6

sizeof(A) = 3, gcc,

 

⑤整个结构体的总大小为其最宽基本类型的整数倍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值