计算结构体大小(字节对齐)

一,默认对齐方式
字节对齐的细节和具体编译器实现相关,但一般而言,满足以下三个准则(也是VC默认对齐方式):
1,结构体变量的首地址能够被其最宽基本类型成员的大小所整除(0能被任意整数整除);
2,结构体每个成员相对于结构体首地址的偏移量都是该成员类型大小的整数倍,如有需要编译器会在成员之间加上填充字节;
3,结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

二,用户自定义对齐方式
修改对齐方式:
1,静态修改:在VS IDE中,通过Project -> Settings -> C/C++ -> Category:Code Generation -> Struct member alignment进行修改,默认为8字节。
2,动态修改:VC中提供了#pragma pack(n)来设定变量以n字节对齐,n的取值一般为2^n(n>=0)。

n字节对齐就是说变量存放的起始地址相对于结构体首地址的偏移量有两种情况:
1,如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式;
2,如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。
结构体的总大小也分两种情况:
1,如果n大于等于所有成员变量类型所占用的字节数,那么结构体的总大小必须为占用空间最大的变量占用的空间数的整数倍(默认对齐方式);
2,否则必须为n的整数倍。

自定义对齐方式计算原则:按占位小的来算。每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(n)中较小的一个对齐。若n大于等于占位最大的元素,则按默认对齐方式计算,若n小于占位最大的元素,则按n计算。

eg:
//#pragma pack(push)
#pragma pack(4)// mystruct1按自定义对齐方式计算,n等于4

typedef struct mystruct1
{
char a;
double b; //32位机中double占8个字节
int c;
}mystruct1;

//#pragma pack(pop)
#pragma pack() //mystruct2按默认对齐方式计算

typedef struct mystruct2
{
char a;
double b;
int c;
}mystruct2;

sizeof(mystruct1)结果为16
sizeof(mystruct2)结果为24

mystruct1的内存布局:1***,11111111,1111 //a, b, c
mystruct2的内存布局:1*******,11111111,1111**** //a, b, c

三,复杂类型(如结构)的默认对齐方式
复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,而不是按其总大小来计算对齐,这样在成员是复杂类型时,可以最小化长度。

eg1:
#pragma pack(8)
struct S1
{
char a;
long b;
}S1;
struct S2
{
char c;
struct S1 d; //对齐参数为4字节(long),而不是8(sizeof(S1)),共占8个字节
long long e; //32位机中long long占8个字节
}S2;
#pragma pack() //恢复默认对齐方式

sizeof(S1)结果为8
sizeof(S2)结果为24

S1的内存布局:1***,1111 //a, b
S2的内存布局:1***,1***,1111,****11111111 //c, d.a, d.b, e

分析:
S2 中,c和S1中的a一样,按1字节对齐,而d 是个结构体,它共占8个字节,它按什么对齐呢?对于结构体来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,S1中成员的最大对齐参数为4,所以结构体d按4字节对齐。成员e占8个字节,它默认按8字节对齐,和指定的一样(n=8),所以它对到8字节整数倍的边界上。之前已经使用了12个字节了,所以需填充4个字节,从第16个字节开始放置成员e。这时长度为24,已经可以被8(成员e按8字节对齐)整除。这样一共使用了24个字节。

eg2:
//默认对齐方式
union U
{
char a;
long b;
short c[5];
}U; //联合体各成员首地址相对于联合体首地址的偏移量均为0

struct S
{
char d;
double e;
union hehe f; //对齐参数为4(long),不是10(short*5),共占12个字节
int g;
}S;

sizeof(U)结果为12
sizeof(S)结果为32

U内存布局:1*********** //a 或 1111******** //b 或 1111111111** //c
S内存布局:1*******,11111111,1111111111**,1111 //d, e, f, g //设f此时存储的为成员c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值