结构体字节对齐深入理解

1 篇文章 0 订阅
1 篇文章 0 订阅

先介绍下几个概念:
自身对齐值:数据类型本身的对齐值,例如char类型的自身对齐值是1,short类型是2;
结构体或类的自身对齐值:其成员中自身对齐值最大的那个值;
指定对齐值:编译器或程序员指定的对齐值;
有效对齐值:自身对齐值和指定对齐值中较小的那个,我们最终是以这个值进行对齐的。

为什么要对齐:
简单的说就是为了提高访问效率。计算机在存取数据的时候,因为我们的数据在内存中占用的大小是不一样的,假设现在我们将一个char(一个字节)数据和一个double(8个字节)的数据读出,而一次只能读出4个字节,这样我们要读三次才能将所有数据读出,如图所示,

我们读取这两个数据读了三次,而且这个double型数据会被切成了三段,读完之后,我们还需要进行拼接,这样读取一个数据就变得复杂了,效率就变低了。
如果我们按4字节对齐,就如下图所示,这样我们的double数据只需要两次就能读出,且拼接也简单得多。
在这里插入图片描述
到底怎么对齐呢?
首先我们要知道以几字节对齐,即我们的有效对齐值是几。以几字节对齐,可以理解为就是一次可以放几字节的数据,如上图,以4字节对齐,就是一次可以放四个字节,然后我们再把我们的成员按顺序一个个放进去,放不进去,就放到下一次,可以空余,不可溢出。如果我们的数据比我们的对齐值还大怎么办呢?这时我们需要把它分割成与有效对齐值一样大再放进去,要是分不匀怎么办?可以告诉你这种情况是不存在的,因为我们只能以1、2、4、8、16对齐(笔者实验到32就报错了),我们的基本数据类型的大小也是1、2、4、8,所以不存在分不匀。

下面我们用代码实验下:

#include<stdio.h>
//#pragma pack(4)
void main(void){
	
	struct s1{	
		char a;
		char b;
		char c;	
	}s1;
	
	struct s2{
		char a;
		short b;
		char c;
	}s2;
	
	struct s3{
		char a;
		int b[8];
		char c;	
	}s3;

	struct s4{
		char a;
		double b;
		char c;
	}s4;
	
	struct s5{
		char a;
		short b;
		struct s4 c;
	}s5;
	
	printf("s1:%d \n",(int)sizeof(s1));
	printf("s2:%d \n",(int)sizeof(s2));
	printf("s3:%d \n",(int)sizeof(s3));
	printf("s4:%d \n",(int)sizeof(s4));
	printf("s5:%d \n",(int)sizeof(s5));
}

执行结果:
s1:3
s2:6
s3:40
s4:24
s5:32

分析:
s1:自身对齐值为1,有效对齐值也是1,所以大小为1+1+1=3
s2:自身对齐值为2,有效对齐值也是2,所以大小为2+2+2=6
s3:数组b可以看做是8个int型数,所以自身对齐值为4,大小为4+4X8+4=40
s4:自身对齐值为8,有效对齐值也是8,所以大小为8+8+8=24
s5:这里面还有一个结构体s4,找对齐值时需要看s4里面的成员,而不是整个大小,s4成员最大的为8,s5其他成员最大为2,所以s5的自身对齐值为8,有效对齐值也是8,另外需要注意的s4成员不能补到s5的其他成员后面,所以s5的大小为8+(8+8+8)=32

看完上面的分析也许你会有疑问,为什么自身对齐值都和有效对齐值一样呢,那指定对齐值是多少呢?在GCC中是没有默认指定值的,所以有效对齐值就和自身对齐值一样了,我们将指定对齐值设为4,再实验一次,将上面代码的//#pragma pack(4)的屏蔽去掉即可。

执行结果:
s1:3
s2:6
s3:40
s4:16
s5:20

分析:
s1:自身对齐值为1,指定对齐值是4,有效对齐值,是1,所以大小为1+1+1=3
s2:自身对齐值为2,指定对齐值是4,有效对齐值,是2,所以大小为2+2+2=6
s3:自身对齐值为4,指定对齐值是4,有效对齐值,是4,所以大小为4+4X8+4=40
s4:自身对齐值为8,指定对齐值是4,有效对齐值,是4,所以大小为4+(4+4)+4=16
s5:自身对齐值为8,指定对齐值是4,有效对齐值,是4,所以大小为4+(4+(4+4)+4)=20

你会发现我们再进行结构体字节对齐时,空了很多内存,所以结构体对齐是一种空间换时间的做法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值