关于字节(内存)对齐

原理

在特定平台特定读取模式下,cpu并不会随机读取内存,比如读取结构体数据时,会以结构体首地址作为参考点,位移x*n(n为处理字长,这个跟编译指令里设置字节对齐值不是一个概念),故一但出现读取奇数地址且长度大于1的数据时,就可能会出现读取一个数据会读取多次的现象,通常,编译器会对结构体的每个字段进行字节对齐,使其达到n,一次即可读取,从而提高cpu读取效率。

优缺点

优点:

  1. 提高读取特定数据效率
  2. 运用得当,在默认情况下能节省空间

缺点:

  1. 占用额外无用空间,这也是空间换时间的弊端

应用场景

编译器所做的字节对齐优化,在特定场景中,我们并不期望有。比如在网络协议模块,由于这些协议字段经常会有变动,但如果按照默认对齐方式的话,程序修改会很麻烦。比如客户端和服务端的对接会遇到问题,不同平台很难确定读取或是写入的地址。因此,通常服务协议的结构体都不按默认对齐方式,你会看到有:

#pragma pack(push,1) 
...
#pragma pack(pop)

这一对编译指令,这样修改协议会简单很多。那为什么默认对齐字节不是1而是4呢?这样不仅省空间,还能解决一些麻烦的问题。笔者在原理中已经提到了,在特定平台特定的读取模式下,这样可能会降低cpu读取内存的效率。

例子

先介绍三个概念:自身对齐值、指定对齐值、有效对齐值。
自身对齐值:数据类型本身的对齐值,例如char类型的自身对齐值是1,short类型是2;
指定对齐值:编译器或程序员指定的对齐值,32位单片机的指定对齐值默认是4;
有效对齐值:自身对齐值和指定对齐值中较小的那个。
对于结构体
1、不但结构体的成员有有效对齐值,结构体本身也有对齐值,这主要是考虑结构体的数组,对于结构体或者类,要将其补齐为其有效对齐值的整数倍。结构体的有效对齐值是其最大数据成员的自身对齐值;
2、存放成员的起始地址必须是该成员有效对齐值的整数倍。
具体看下下面的例子读者应该就会明白。

#include<iostream>
using namespace std;
#pragma pack(push,1)//可为1,2,4,8
struct s1
{
	char c1;
	char c2;
	int x;
};
struct s2
{
	char c1;
	int x;
	char c2;
};
struct s3
{
	char c1;
	int x;
	short sx;
	char c3;
};

int main()
{
	char test;
	cout << "s1:"<<sizeof(s1)<<endl;
	cout << "s2:" << sizeof(s2) << endl;
	cout << "s3:" << sizeof(s3) << endl;
	system("pause");
	return 0;
}
#pragma pack(pop)

当对齐字节为1时:
在这里插入图片描述
当对齐字节为4(默认)时:
在这里插入图片描述

参考引用:
字节对齐参考
结构体对齐方式参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王富贵9527

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值