结构体内存对齐

https://blog.csdn.net/qq_42195954/article/details/90116940

一、结构体的对齐规则:

1.结构体的第一个数据成员在偏移量为0的地址处。
2.其他成员放在对齐数的整数倍地址处。对齐数取编译器默认和该数据成员大小的min,vs默认值是8,Linux没有默认对齐数。
3.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,也就是max(成员变量大小)。
4.结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

例1

struct s1
{
	double a;
	char b;
	int c;
};

例一
数据成员对齐数 = min( 编译器默认对齐数,该数据类型大小 )

  1. double a; // 地址从0开始,前8个字节存的是double
  2. char b; // min(8 ,1) = 1 ,此时下标是8,8是1的整数倍,第9个字节存的是char
  3. int c; // min(8,4) = 4 ,此时下标是9,9不是4的整数倍,补3个字节,此时下标是12,存入int
  4. 共存了8+4+4=16个字节,整体对齐系数 = min(8,max( double, char, int )) = 8,16是8的整数倍,不用补空字节,分析完成。
    综上所述,该结构体占有16个字节。

例2

struct s2
{
	char a;
	struct s1 s11;
	double b;
};

在这里插入图片描述
数据成员对齐数 = min( 编译器默认对齐数,该数据类型大小 )

  1. char a; // 地址从0开始,第一个字节存的是char
  2. struct s1 s11; // min( 8 ,max(double,char,int)) = 8 ,此时下标是1,1不是8的整数倍,补7个空字节,再存入s11(16个字节)
  3. double b; // min(8,8) = 8 ,此时下标是24,24是8的整数倍,再存入double
  4. 共存了1+7+16+8=32个字节,整体对齐数 = min( 8,max( char, struct s1, double )) = 8,32是8的整数倍,不用补空字节,分析完成。
    综上所述,该结构体占有32个字节。

二、修改默认对齐数:预处理指令: #pragma

#pragma pack(n) 作用:C编译器将按照n个字节对齐。
#pragma pack() 作用:取消自定义字节对齐方式。

#pragma pack(push,1) 作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为一个字节对齐
#pragma pack(pop) 作用:恢复对齐状态

因此可见,加入push和pop可以使对齐恢复到原来状态,而不是编译器默认,可以说后者更优,但是很多时候两者差别不大

#pragma pack(push) //保存对齐状态
#pragma pack(4)//设定为4字节对齐
相当于 #pragma pack (push,4)

例1

struct s1
{
	double a;
	char b;
	int c;
};

#pragma pack(4)
struct s2
{
	char a;
	struct s1 s11;
	double b;
};
#pragma pack()

int main()
{
	printf("%d\n", sizeof(struct s1));
	printf("%d\n", sizeof(struct s2));
	system("pause");
	return 0;
}

s1在上面例一已经分析过,这里主要分析s2
在这里插入图片描述
数据成员对齐数 = min( 修改后的默认对齐数(4) ,该数据类型大小 )

  1. char a; // 地址从0开始,第一个字节存的是char
  2. struct s1 s11; // min( 4 ,max(double,char int)) = 4 ,此时下标是1,1不是4的整数倍,补3个空字节,再存入s11(16个字节)
  3. double b; // min(4,8) = 4 ,此时下标是20,20是4的整数倍,再存入double
  4. 共存了1+3+16+8=28个字节,整体对齐数 = min(4,max( char, struct s1, double )) = 4,28是4的整数倍,不用补空字节,分析完成。
    综上所述,该结构体占有28个字节。

例2

例如:

#pragma pack(1)
struct sample
{
char a;
double b;
};
#pragma pack()

若不用#pragma pack(1)和#pragma pack()括起来,则sample按编译器默认方式对齐(成员中size最大的那个)。即按8字节(double)对齐,则sizeof(sample)==16.成员char a占了8个字节(其中7个是空字节);

若用#pragma pack(1),则sample按1字节方式对齐sizeof(sample)==9.(无空字节),比较节省空间啦,有些场和还可使结构体更易于控制。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值