1.内存数据对齐的原因:
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
2.数据对齐原则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节, 则要从4的整数倍地址开始存储),基本类型不包括struct/class/uinon。
2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)。
3、收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的"最宽基本类型成员"的整数倍.不足的要补齐.(基本类型不包括struct/class/uinon)。
4、sizeof(union),以结构里面size最大元素为union的size,因为在某一时刻,union只有一个成员真正存储于该地址。
3.具体实例:
#include <iostream> using namespace std; union a { int a_int1; double a_double; //8字节 int a_int2; char ch; //由原则4,a的大小为8 }; struct b { a a1; //[0]...[7] , char y; //[8] //由原则3,"最宽基本类型成员"为a中的double,从而b的大小为8的整数倍,所以b的大小为16 }; class c { int c_double; //[0]...[4] b b1; //[8]...[23] 原则2:与b的内部的最大元素的整数倍开始存储 char ch; //[24] //由原则3,"最宽基本类型成员"为b中,即b里面a的double,c的大小为8的整数倍,所以c的大小为32 }; struct usc { char ch; //[0] b b2; //[8]...[23] 原则2:与b的内部的最大元素的整数倍开始存储 a a2; //[24]...[31] c c2; //[32]...[63] char ch1; //[64] //"最宽基本类型成员"为a中的double 或者 即b里面a的double 或者 c里面的b里面的double //由原则3,usc的大小为8的整数倍,所以usc的大小为72 }; void main() { cout<<"sizeof(a)= "<<sizeof(a)<<endl; cout<<"sizeof(b)= "<<sizeof(b)<<endl; cout<<"sizeof(c)= "<<sizeof(c)<<endl; cout<<"sizeof(usc)= "<<sizeof(usc)<<endl; }
总结:
从“struct/class以及union内存对齐原则”可以得出:在struct/class/union中定义变量时,长度小的变量先定义,长度大的变量后定义,可以节省内存。
4.#pragma pack()
在代码前加一句#pragma pack(1),#pragma pack(1)是告诉编译器,所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则.
5.位域(特例)
#include<iostream> using namespace std; #pragma pack(1) struct A { //unsigned short i:8; char t:4; //位域的意思:表示t占4个位 char k:4; unsigned long m; //char k:4; unsigned short i:8; //unsigned short j:8; } ; #pragma pack() int main(){ A b; cout<<sizeof(b)<<endl; system("pause"); return 1; }
不考虑边界对齐,大小为7,tk他俩占第一个字节,i占第二个字节,m从四字节开始占四个字节,问题是m为什么不从第三字节开始:是因为第二三字节的short被划分为2个字节类型的位模式了,m改为unsigned short m:8;就可以从第三字节开始了。
同理:
#include<iostream> using namespace std; #pragma pack(1) struct A { //unsigned short i:8; char t:4; //char k:4; unsigned long m; char k:4; unsigned short i:8; //unsigned short j:8; } ; #pragma pack() int main(){ A b; cout<<sizeof(b)<<endl; system("pause"); return 1; }
输出就是8.
#include<iostream> using namespace std; #pragma pack(1) struct A { //unsigned short i:8; char t:4; char k:4; unsigned long m; //char k:4; unsigned short i:8; unsigned short j:8; } ; #pragma pack() int main(){ A b; cout<<sizeof(b)<<endl; system("pause"); return 1; }
输出是7.
#include<iostream> using namespace std; #pragma pack(1) struct A { unsigned short i:8; char t:4; char k:4; unsigned long m; //char k:4; //unsigned short i:8; unsigned short j:8; } ; #pragma pack() int main(){ A b; cout<<sizeof(b)<<endl; system("pause"); return 1; }
输出是9.
总结:位域将原类型占用的字节分成相应的位数,只有后面是相同的类型才能继续占用没有使用的位数;如果是不同的类型就需要按前面类型原有的字节来往后顺延到本类型开始的字节位置。
补充:
指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。
#pragma pack规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的 数值和结构体的自然对齐长度中比较小的那个进行。就是说,当#pragma pack的值等于或超过所有数据成员长度的时 候,这个值的大小将不产生任何效果。
实例:具体解释:
#pragma pack(4) class TestB { public: int aa; //第一个成员,放在[0,3]偏移的位置, char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。 short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。 char c; //第四个,自身长为1,放在[8]的位置。 }; 这个类实际占据的内存空间是9字节 类之间的对齐,是按照类内部最大的成员的长度,和#pragma pack规定的值之中较小的一个对齐的。 所以这个例子中,类之间对齐的长度是min(sizeof(int),4),也就是4。 9按照4字节圆整的结果是12,所以sizeof(TestB)是12。
#pragma pack(2)
class TestB { public: int aa; //第一个成员,放在[0,3]偏移的位置, char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。 short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。 char c; //第四个,自身长为1,放在[8]的位置。 }; //可以看出,上面的位置完全没有变化,只是类之间改为按2字节对齐,9按2圆整的结果是10。 //所以 sizeof(TestB)是10。
#pragma pack(push) //保存对齐状态 #pragma pack(2) struct A { char b; int a; short c; }; #pragma pack(pop) //恢复对齐状态 int main() { cout << sizeof(A) 分析: 这里指定了对齐长度为2; b的对齐长度为1字节,存放地址:0x0000 a的对齐长度为2字节,存放地址:0x0002 ~ 0x0005;//数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。 c的对齐长度为2字节, 存放地址:0x0006 ~ 0x0007; A的对齐方式为2,(这里8是2的倍数,因此不用补0) 所以sizeof(A)为2的整数倍:8
发表评论
-
set容器的反向迭代器
2013-05-02 16:56 3755#include <iostream> #in ... -
对于CRITICAL_SECTION用法的介绍和理解[转]
2013-04-08 11:50 2191很多人对CRITICAL_SECTION ... -
二维数组知识
2012-09-15 17:20 821二维数组和指针⑴ 用 ... -
Realloc的使用
2012-08-14 11:04 833realloc 用过很多次了。 ... -
extern C的由来
2012-08-09 10:14 698时常在cpp的代码之中看到这样的代码: #ifdef ... -
C++类对象的创建过程
2012-07-26 16:02 941分配空间(Allocation) ... -
静态数据成员和静态成员函数
2012-07-26 15:04 3115静态类成员包括静态数据成员和静态函数成员两部分。 与 ... -
复制构造函数(拷贝构造函数)以及深浅拷贝
2012-07-25 22:39 1433对于普通对象而言复制是很简单的,一般是将变量或者常量赋值给某 ... -
cin、cin.get、cin.getline()、getline()、gets()的用法【转】
2012-07-24 20:05 833学C++的时候,这几个输入函数弄的有点迷糊;这里做个小结,为了 ... -
编程笔记(07-24)
2012-07-24 15:15 6691 #include < stdio.h ... -
堆、栈解疑
2012-07-12 21:53 586一、预备知识—程序的内存分配 一个由C/C++编译的程序 ... -
指针和内存分配的深度理解
2012-07-12 18:57 1033一 :关于指针和堆的内存分配 先来介绍一下指针: 指针一种 ... -
数组指针和指针数组
2012-07-12 18:56 1189先看一下基本的形式,我们从这里起步! ----------- ... -
const指针和指向const的指针
2012-07-12 10:30 2124指向const对象的指针 ... -
typedef的学习
2012-07-11 15:03 744typedef,顾名思义,为“类型定义”,可以解释为:将一种数 ... -
函数指针和指针函数
2012-07-11 11:21 600【函数指针】 ... -
Define学习
2012-07-11 10:12 1075宏替换是C/C++系列语言的技术特色,C/C++语言提 ... -
sizeof 深研
2012-07-11 09:39 6721、什么是sizeof 首先看一下sizeof ... -
指针深究
2012-07-09 21:55 596在说指向指针的指针之前,不得不说指向变量的指针。先看如下示例: ... -
C语言文件使用方式详解
2012-07-04 10:23 770文件的打开(fopen函数) f ...
相关推荐
ztsc_109339.apk
永磁同步电机的高频正弦电压注入的速度观测,Simulink,PMSM,高频正弦。
智慧燃气发展研究报告
如何通过智能卡读写器SDK接入鸿蒙操作系统?通过智能卡读写器提供的SDK范例可以将智能卡读写器接入在运行鸿蒙操作系统的智能终端设备上。
谭浩强编写的《C程序设计(第五版)》PPT、书中源码、习题答案以及习题库
人力资源+大数据+薪酬报告+涨薪调薪,在学习、工作生活中,越来越多的事务都会使用到报告,通常情况下,报告的内容含量大、篇幅较长。那么什么样的薪酬报告才是有效的呢?以下是小编精心整理的调薪申请报告,欢迎大家分享。相信老板看到这样的报告,一定会考虑涨薪的哦。
分布式驱动汽车稳定性控制。 采用分层式直接横摆力矩控制,上层滑模控制,下层基于轮胎滑移率最优分配。 滑模控制跟踪横摆角速度和质心侧偏角误差。 七自由度整车模型输出实际质心侧偏角和横摆角速度,二自由度模型输出理想质心侧偏角和横摆角速度。 附m文件,有参考文献和说明文档
注意:此文档为最终版本,方便大家记录,但更新主要还是在博客更新
汇川.H5U框架程序,汇川TIT700系列触摸屏框架程序 1.汇川H5U-A8系列cpu 自制封装多个FB功能块程序,轴控制功能块,气缸动作报警功能块,XY矩阵功能块,等等。 只需写动作步序,其他全部调用FB 和HMI可以无实物仿真 仿真HMI地址127.0.0.1 A1349.H5U原框架
学生作业-作业打卡盖章。该项目为html前端项目,依据学生作业提交情况,通过点击名字进行打卡盖章。涉及html、js、css,其中js中涉及监听函数;窗口中的列表数据来源于data.jso,可自行修改
Spring面试专题.pdf
2025年蓝色简约时尚婚礼邀请函模板
深层过滤纸板是一种由纤维素材料制成的平板或薄片,具有过滤液体或气体的能力。它通常由纤维素纤维(如木浆)经过湿法造纸工艺制成,形成一张薄而均匀的纸板。深层过滤纸板设计用于过滤任何类型的液体,包括葡萄酒、油、啤酒和果汁等,广泛应用于食品饮料、制药、化工等领域。 随着酿酒行业和饮料行业的不断壮大,对深层过滤纸板的需求也在增加。深层过滤纸板常用于过滤液体中的杂质和固体颗粒,确保产品的质量和纯度。因此,这些行业的发展推动了过滤纸板的需求。为了满足酿酒行业和饮料行业对过滤效果、速度和成本的不断追求,深层过滤纸板制造商进行了技术创新和改进。他们不断改良过滤纸板的材料、结构和制造工艺,以提高其过滤效率和性能,同时降低生产成本。环保意识的提升推动了过滤纸板行业朝着绿色、可持续发展的方向发展。包括可降解材料的应用,再生纤维的使用以及生产过程的绿色化都是行业发展的趋势。 目前在全球范围内,工业化的发展仍处于高速阶段,企业在生产过程中要求更高的过滤处理标准,从而促进了深层过滤纸板行业的发展。随着生物技术产业的发展,越来越多的实验室需要使用过滤纸板进行细胞和菌群的分离,同时也需要更高精度的滤料来处理许多疾病的检
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
easy-interceptor修改请求头和响应头.zip
代码复现;冷热电气多门互补的微能源网鲁棒优化调度MATLAB复现 随着能源结构调整,集成风/光等可再生能源输入、冷热电气等多种能源互补输出的微能源网得到了逐步发展,如何协调调度微能源网内冷热电气源网荷成为当前研究热点。 建立了冷热电气多能互补的微能源网在孤岛/并网模式下的协调调度模型,并利用供热/供冷系统的热惯性和热/冷负荷的柔性,发挥供热/供冷系统的“储能”功能,以电转气(P2G)装置实现电—气网络双向互通。 模型采用鲁棒线性优化理论将随机优化模型进行确定性转化,取得经济性和鲁棒性的适当折中。 算例仿真验证了温度负荷储能特性对微能源网灵活调度的优化作用和鲁棒性指标对优化结果的协 调作用。 关键词:微能源网;多能互补;温度负荷;储能特性;鲁棒优化
三电平T型变器双闭环PI控制-调制实现在60度坐标系 变器 减少了普通SVPWM的矢量计算时间,在60度坐标系完成高效计算,控制效果很好。 可以发参考资料
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
箱线图(Box Plot)是一种用于展示数据分布的图形工具,能够有效地显示数据的集中趋势和离散程度。以下是箱线图的主要特点和组成部分: 主要特点 数据分布:箱线图可以清晰地展示数据的中位数、四分位数和潜在的异常值。 多组比较:可以将多组数据在同一张图中进行可视化,便于比较不同组之间的差异。 易于理解:由于其结构清晰,读取和理解相对简单。 使用场景 数据分析:用于探讨数据的分布和变化,识别异常值。 统计总结:在数据报告和研究中,用于直观表达数据特征。
ChromeDriver 是一个用于自动化 Chrome 浏览器的工具,它是由 Selenium WebDriver 提供支持的。在测试领域,尤其是Web应用程序的自动化测试中,ChromeDriver扮演着至关重要的角色。标题"chromedriver version 118.0.5993.70"表明这是 ChromeDriver 的一个特定版本,版本号为118.0.5993.70,通常这样的更新会带来性能优化、新功能以及对Chrome浏览器新版本的支持。 描述中的“chromedriver测试版本”意味着这可能是一个用于测试目的的构建,可能包含了最新的改进或者尚未广泛发布的特性。开发者和测试工程师会使用这样的测试版本来确保他们的自动化测试脚本能够兼容即将推出的 ChromeDriver 正式版本。 标签“测试 chromedriver”进一步强调了该软件在测试环境中的应用,特别是与 Chrome 浏览器的自动化测试相关的场景。ChromeDriver 允许测试人员通过编写 Selen。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。