当前位置: 首页 > news >正文

【补充1】字节对齐

文章目录

  • 1.字节对齐的基本概念
  • 2.字节对齐规则
  • 3.实践出真知(加大难度)
  • 4 位域

1.字节对齐的基本概念

(1)现代计算机中内存空间都是按照byte划分的,
从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,
但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,
这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。(2)对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。
一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。

显然在读取效率上下降很多。

2.字节对齐规则

先来看一个简单的例子

struct DATA
{short flag;int   data;
};
printf("DATA sizeof:%d\n", sizeof(DATA));
上面的输入会是多少呢?这里的输出是size=8,亲们可以复制代码测试看输出是多少。
那么问题来了,为什么这个结构的大小不是short(2字节)+int(4字节)=6字节呢?请看下面的对齐规则你便明白了。

(1).数据类型自身的对齐值:
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
(2).结构体的自身对齐值:
其成员中自身对齐值最大的那个值(默认)。
(3).指定对齐值(这个对齐的值是可以人为控制的):

>#pragma pack(value) 	// 作用:C编译器将按照n个字节对齐。
#pragma pack()			// 作用:取消自定义字节对齐方式。
//或者
#pragma pack(push, value)	// 作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为value个字节对齐
#pragma pack(pop)           // 作用:恢复对齐状态
// 此时就使用指定对齐值 value。
// 两者区别:加入push和pop可以使对齐恢复到原来状态,而不是编译器默认;
//         可以说后者更优,但是很多时候两者差别不大。

(4).数据成员、结构体的有效对齐值:
自身对齐值和指定对齐值中取最小的那个值作为对齐值。

在倒回去看例子,结构体DATA的对齐取的是4(int 4字节较大),所以前面的short就变成了占4个字节空间,所以sizeof(DATA)输出的是8了。
为什么short就变成占4字节空间了?刚开始也不太明白为什么short就变成占4字节空间了。继续看完下面的实践便明白了。

3.实践出真知(加大难度)

struct DATA1
{short 	flag1;int	  	data;short 	flag2;
};struct DATA2
{short 	flag1;short 	flag2;int     data;
};printf("DATA1 size:%d\n", sizeof(DATA1));
printf("DATA2 size:%d\n", sizeof(DATA2));

运行上面的程序,结果将是:

DATA1 size:12
DATA2 size:8

为什么会出现这样的结果呢?分析:
首先,两个结构体取的对齐数是4(int 4字节较大),在结构体DATA1进行存放时,假设是从地址0x00开始存放的,flag1(short)存放在在0x00-0x01里面,在前四个字节里面还剩下两个字节;紧接着是data(int),data(int)是四个字节,剩下的两个字节不够装data了。所以data(int)就新开了四个字节存放,所以他的地址就是0x04-0x07;最后是flag2(short),由于它只有两个字节,即0x08-0x09,他为了满足四字节对齐,所以它也空了两个字节。最终DATA1的内存为0x00-0x11;所以sizeof(DATA1)=12。
我们在来看DATA2,flag1(short)存放在0x00-0x01里面,前四个字节里面还剩下两个字节,紧接着是flag2(short),flag2(short)是两个个字节,前两剩下的两个字节正好存放下,存放在0x02-0x03,所以前四个字节将flag1和flag2存放好了;最后是data(int),data在紧接着的四个字节里存放,即0x04-0x07,所以最终DATA2的内存为0x00-0x07;所以sizeof(DATA2)=8。

[拓展]如何让结构体DATA1也变为8字节呢?那就是人为控制字节对齐数。
将上面的结构体改为如下

#pragma pack(push, 2)
struct DATA1
{short 	flag1;int	  	data;short 	flag2;
};
#pragma pack(pop)struct DATA2
{short 	flag1;short 	flag2;int     data;
};printf("DATA1 size:%d\n", sizeof(DATA1));
printf("DATA2 size:%d\n", sizeof(DATA2));

修改后的输出为:

DATA1 size:8
DATA2 size:8

如上,我们便将DATA1的字节对齐数设置为2,这边便控制了DATA1的的字节数为8;可以在字节对齐数为2的基础上在此分析其构成,我这里就不在阐述了。

4 位域

结构体中,还有一个操作叫做位域,

struct A
{char  a : 2;short b : 3;int   c : 4;
};

在结构体A中,a的8位只有2位有效,b的16位只有3为有效,c的32位只有4位有效。
注意:位域必须存储在同种数据类型所占的字节中,不能跨两个同种数据类型所占的字节数。 也就是说,后面的数字不能大于前面类型的位数。 位域不会影响 sizeof() 的规则

http://www.lryc.cn/news/354639.html

相关文章:

  • Java数据库连接(JDBC)
  • 记录一次cas单点登录的集成
  • 【吊打面试官系列】Java高并发篇 - 什么是乐观锁和悲观锁?
  • 机器学习之词袋模型
  • 【C++/STL】vector(常见接口、模拟实现、迭代器失效)
  • Spring Boot Web 开发:MyBatis、数据库连接池、环境配置与 Lombok 全面解析
  • 【UE5.1 多线程 异步】“Async Blueprints Extension”插件使用记录
  • 【已解决】在jupyter里运行torch.cuda.is_available(),显示True,在pycharm中运行却显示false。
  • Flutter 中的 Scrollbar 小部件:全面指南
  • 【华为】将eNSP导入CRT,并解决不能敲Tab问题
  • 实验二 电子传输系统安全-进展2
  • JavaScript 获取 HTML 中特定父元素下的子元素
  • 等保服务是一次性服务吗?为什么?怎么理解?
  • 全网首发UNIAPP功能多的iapp后台源码
  • 【搜索方法推荐】高效信息检索方法和实用网站推荐
  • 面试被问到不懂的东西,是直接说不懂还是坚持狡辩一下?
  • Flutter 中的 StatefulBuilder 小部件:全面指南
  • mail发送接口API如何使用?怎么调用接口?
  • DOS学习-目录与文件应用操作经典案例-attrib
  • STP简介
  • java调用科大讯飞在线语音合成API --内附完整项目
  • Vuex 页面刷新数据丢失怎么解决
  • 如何使用Cloudways搭建WordPress网站
  • Lora理解
  • EtherCAT总线掉线如何自动重启
  • RabbitMQ有哪些优缺点
  • word页眉线如何置于文字上方
  • CTF-web-攻防世界-2
  • 【深度学习】YOLOv8训练,交通灯目标检测
  • 紧固件松动的危害及原因——SunTorque智能扭矩系统