c++中的对齐问题

c++中的对齐问题

需要对齐的原因

尽管内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的.它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度.

现在考虑4字节存取粒度的处理器取int类型变量(32位系统),该处理器只能从地址为4的倍数的内存开始读取数据。

假如没有内存对齐机制,数据可以任意存放,现在一个int变量存放在从地址1开始的联系四个字节地址中,该处理器去取数据时,要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址),然后从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器.这需要做很多工作.

bg1

对齐的规则

有效对齐值:是 #pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位

注意:
#pragma pack(n)中的n可以取(1 , 2 , 4 , 8 , 16)中的任意一值。

2)规则:

  • 结构体变量的首地址是有效对齐值(对齐单位)的整数倍。

  • 结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个的整数倍,如有需要编译器会在成员之间加上填充字节。

  • 结构体的总大小为有效对齐值的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

  • 结构体内类型相同的连续元素将在连续的空间内,和数组一样。

运用上面的规则,下面通过实际的例子进行计算。

例1:

#include <iostream>struct MyStruct {char c;int i;short s;
};int main()
{MyStruct obj;std::cout << "start addr of obj = " << (void*)&obj << std::endl;std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;std::cout << "offset of s = " << offsetof(MyStruct,s) << std::endl;std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

执行结果如下:

start of obj = 0x7fff2e8d1e94
offset of c = 0
offset of i = 4
offset of s = 8
sizeof MyStruct = 12

结构中最长的数据类型是int,长度也为4。因此结构体的有效对齐值是4。

对于c变量而言,没有悬念,将排在0偏移地址处。

对于变量i,类型为int,长度为4,int和有效对齐值的最小值为4,因此i需要排布在4的整数倍上,因此第一个符合要求的偏移量就是4。

对于变量s,类型为short,长度为2,short和有效对齐值二者中的最小值为2,第一个符合要求的地址为8。

到目前为止,使用的空间大小是10,而结构体大小需要满足有效对齐值的整数倍,因此需要2个填充,因此结构体最终大小是12。

MyStruct分布

例2:

#include <iostream>
#pragma pack(2)
struct MyStruct {char c;int i;short s;
};int main()
{MyStruct obj;std::cout << "start addr of obj = " << (void*)&obj << std::endl;std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;std::cout << "offset of s = " << offsetof(MyStruct,s) << std::endl;std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

执行结果如下:

start addr of obj = 0x7fff488e3418
offset of c = 0
offset of i = 2
offset of s = 6
sizeof MyStruct = 8

首先#pragma pack设置的对齐值是2,结构中最长的数据类型是int,长度也为4。因此结构体的有效对齐值是2。

对于c变量而言,没有悬念,将排在0偏移地址处。

对于变量i,类型为int,长度为4,int和有效对齐值的最小值为2,因此i需要排布在2的整数倍上,因此第一个符合要求的偏移量就是2。

对于变量s,类型为short,长度为2,short和有效对齐值二者中的最小值为2,第一个符合要求的地址为6。

到目前为止,使用的空间大小是8,已经满足结构体大小是有效对齐值的整数倍的要求。

MyStruct分布2

#include <iostream>
#pragma pack(1)
struct MyStruct {char c;int i;short s;
};int main()
{MyStruct obj;std::cout << "start addr of obj = " << (void*)&obj << std::endl;std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;std::cout << "offset of s = " << offsetof(MyStruct,s) << std::endl;std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

执行结果如下:

start addr of obj = 0x7ffe96c067a9
offset of c = 0
offset of i = 1
offset of s = 5
sizeof MyStruct = 7

首先#pragma pack设置的对齐值是1,结构中最长的数据类型是int,长度也为4。因此结构体的有效对齐值是1。

对于c变量而言,没有悬念,将排在0偏移地址处。

对于变量i,类型为int,长度为4,int和有效对齐值的最小值为,因此i需要排布在2的整数倍上,因此第一个符合要求的偏移量就是1。

对于变量s,类型为short,长度为2,short和有效对齐值二者中的最小值为2,第一个符合要求的地址为5。

到目前为止,使用的空间大小是7,已经满足结构体大小是有效对齐值的整数倍的要求。

MyStruct分布3

例4:

#include <iostream>
#include <emmintrin.h>struct MyStruct {char c;__m128i i;
};int main()
{MyStruct obj;std::cout << "start addr of obj = " << (void*)&obj << std::endl;std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

执行结果如下:

start addr of obj = 0x7fff9d47cd90
offset of c = 0
offset of i = 16
sizeof MyStruct = 32

首先,结构中最长的数据类型是__m128i,长度为16。因此结构体的有效对齐值是16。

对于c变量而言,没有悬念,将排在0偏移地址处。

对于变量i,类型为__m128i,长度为16,__m128i和有效对齐值的最小值为16,因此i需要排布在2的整数倍上,因此第一个符合要求的偏移量就是16。

MyStruct分布4

例5:

#include <iostream>
#include <emmintrin.h>#pragma pack(8)
struct MyStruct {char c;__m128i i;
};int main()
{MyStruct obj;std::cout << "start addr of obj = " << (void*)&obj << std::endl;std::cout << "offset of c = "  << offsetof(MyStruct,c) << std::endl;std::cout << "offset of i = " << offsetof(MyStruct,i) << std::endl;std::cout << "sizeof MyStruct = " << sizeof(MyStruct);
}

执行结果如下:

start addr of obj = 0x7ffddbec2c40
offset of c = 0
offset of i = 8
sizeof MyStruct = 24

首先#pragma pack设置的对齐值是8,结构中最长的数据类型是__m128i,长度为16。因此结构体的有效对齐值是8。

对于c变量而言,没有悬念,将排在0偏移地址处。

对于变量i,类型为__m128i,长度为16,__m128i和有效对齐值的最小值为8,因此i需要排布在2的整数倍上,因此第一个符合要求的偏移量就是8。

MyStruct分布5

总结

  • 为了高效的访问内存数据,通常需要对内存数据进行对齐。
  • #pragma pack(n)用于设置的对齐有效值,如果设置比结构体的最长成员还大的对齐值将是无效的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/70243.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搜索二维矩阵 II

题目链接 搜索二维矩阵 II 题目描述 注意点 矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 解答思路 最初想到使用深度优先遍历剪枝实现&#xff0c;但是运行后超出时间限制了可以直接遍历整个矩阵查找&#xff0c;虽然不超时…

Excel VSTO开发-目录

1 VSTO简介2 建立Excel VSTO项目3 代码调试4 其他事件5 Excel对象结构6 Range对象7 可视化界面开发8 相关控件9 使用Form窗口10 自定义任务面板11 自定义菜单项 相关代码下载&#xff1a; https://download.csdn.net/download/UruseiBest/88306532?spm1001.2014.3001.5503 学…

使用Java分析器优化代码性能,解决OOM问题

有的时候博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 背景 最近我一直在做性能优化&#xff0c;对一个单机应用做性能优化。主要是涉及到解析和导入导出相关的业务。 大致说一下这个单机应用…

关系型数据库和非关系型数据库

关系型数据库是以关系&#xff08;表格&#xff09;为基础的数据库&#xff0c;它采用了 SQL&#xff08;Structured Query Language&#xff09;作为数据操作语言&#xff0c;常见的关系型数据库包括 MySQL、Oracle、SQL Server 等。 非关系型数据库则是基于文档、键值、列族…

Springboot+Redis执行lua脚本

随着Redis数据库的广泛应用&#xff0c;它在服务器端应用程序中的作用越来越重要。Redis具有快速读写、数据持久化、发布订阅、事务处理等诸多特性&#xff0c;而这些特性使得它在处理高并发、实时数据操作等方面表现出色。然而&#xff0c;单纯使用Redis还不足以满足一些复杂业…

Socks5代理IP:保障跨境电商的网络安全

在数字化时代&#xff0c;跨境电商已成为全球商业的重要一环。然而&#xff0c;随着其发展壮大&#xff0c;网络安全问题也逐渐浮出水面。为了确保跨境电商的安全和隐私&#xff0c;Socks5代理IP技术成为了一项不可或缺的工具。本文将深入探讨Socks5代理IP在跨境电商中的应用&a…

深度优先搜索(dfs)--矩阵部分-leetcode以及常见题

介绍 深度优先搜索&#xff08;Depth-First Search&#xff0c;DFS&#xff09;是一种常用的图搜索算法&#xff0c;它用于查找图或树数据结构中的路径或解决问题。下面是深度优先搜索的常见步骤以及一个示例问题&#xff1a; 深度优先搜索的常见步骤&#xff1a; 选择起始节…

如何手动读取 GLTF/GLB 文件

推荐&#xff1a;使用NSDT场景编辑器快速搭建3D应用场景 文件类型 GLTF文件有两种不同的主要文件类型&#xff1a;.gltf和.glb。 GLTF文件本质上只是一个重新命名的json文件&#xff0c;它们通常与包含顶点数据等内容的.bin文件相提并论&#xff0c;但这些内容也可以直接包含…

ElementUI浅尝辄止33:Form 表单

Form 表单&#xff1a;日常业务中很常见&#xff0c;由输入框、选择器、单选框、多选框等控件组成&#xff0c;用以收集、校验、提交数据&#xff0c;常见于表单请求、登录&#xff0c;数据校验等业务操作中 1.如何使用&#xff1f; 包括各种表单项&#xff0c;比如输入框、选…

分布式实时仿真系统-反射内存的应用

为了使分布式实时仿真系统(一个典型代表就行飞行模拟器)达到逼真的仿真效果&#xff0c;在系统内部&#xff0c;往往不仅需要对各种数据模型进行实时解算&#xff0c;而且需要一个延迟时间极低的确定性网络在系统之间传递数据&#xff0c;这样才能让各个子系统之间协调一致地工…

问道管理:分时高抛低吸策略?

分时高抛低吸是股市中的一种买卖战略&#xff0c;也是投资者经常运用的一种方法。这种战略经过剖析图表、股价和时刻&#xff0c;尽可能减少危险&#xff0c;添加收益。下面从多个视点对十二种分时高抛低吸进行剖析。 视点一&#xff1a;什么是分时高抛低吸&#xff1f; 分时高…

报错:为什么数组明明有内容但打印的length是0

文章目录 一、问题二、分析三、解决1.将异步改为同步2.设置延迟 一、问题 在日常开发中&#xff0c;for 循环遍历调用接口&#xff0c;并将接口返回的值进行拼接&#xff0c;即push到一个新的数组中&#xff0c;但是在for循环内部是可以拿到这个新的数组&#xff0c;而for循环…

Selenium 3和JUnit 5中的显示等待与隐式等待

目录 显示等待&#xff08;Explicit Wait&#xff09; 什么是显示等待&#xff1f; 如何实现显示等待&#xff1f; 显示等待条件 隐式等待&#xff08;Implicit Wait&#xff09; 什么是隐式等待&#xff1f; 如何实现隐式等待&#xff1f; 显示等待和隐式等待的区别 …

mapbox 导航记录(release-v2.15分支 纯kotlin)

一、简单使用示例 1. 初始化 MapboxNavigation 初始化时使用 NavigationOptions 设置一些参数&#xff0c;包括accessToken、appMetaData、LocationEngine等&#xff0c;其它还有很多&#xff0c;具体可以详看 NavigationOptions 类的内部。 下面示例中 LocationEngine 使用…

C++ 多线程编程教程:使用 std::thread 和 std::future 进行并发任务管理 ,处理线程超时

C 多线程编程教程&#xff1a;使用 std::thread 和 std::future 进行并发任务管理 引言 多线程编程是一种强大的工具&#xff0c;可以加速计算密集型任务的执行&#xff0c;提高应用程序的性能。C提供了多种多线程编程工具&#xff0c;包括std::thread和std::future&#xff…

【infiniband】用udaddy测试RDMA_CM API通过GID连接

1. 运行ibv_devinfo -vv 找到GID[ 0]。 2.udaddy用1.找到的GID[ 0]测试连接 服务器: rootdebian:~/infiniband/rdma-core-50mlnx1# build/bin/udaddy -f gid -b fe80:0000:0000:0000:e41d:2e03:0051:26d1 udaddy: starting server test.rai->ai_src_addr->sa_famil…

IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -Maven使用前准备

一&#xff0e;Maven准备 注意&#xff1a;IDEA2019.1.x 最高支持Maven的3.6.0 下载地址&#xff1a;http://maven.apache.org/Maven底层使用Java语言编写的&#xff0c;所以需要配置JAVA_HOME环境变量及Path将Maven解压非中文无空格目录下配置MAVEN_HOME环境变量及Path输入【c…

基于AERMOD模型在大气环境影响评价中的实践

AERMOD模型是在美国EPA&#xff08;AMS/EPA&#xff09;在ISC3&#xff08;Industrial Source Complex Model&#xff09;基础上建立开发的高斯稳态扩散模型&#xff0c;是我国《环境影响评价技术导则 大气环境&#xff08;HJ 2.2-2018&#xff09;》技术导则推荐的大气污染物浓…

人工智能的优势:使用 GPT 和扩散模型生成图像

推荐&#xff1a;使用 NSDT场景编辑器快速搭建3D应用场景 世界被人工智能 &#xff08;AI&#xff09; 所吸引&#xff0c;尤其是自然语言处理 &#xff08;NLP&#xff09; 和生成 AI 的最新进展&#xff0c;这是有充分理由的。这些突破性技术有可能提高各种任务的日常生产力。…

Vue前端框架08 Vue框架简介、VueAPI风格、模板语法、事件处理、数组变化侦测

目录 一、Vue框架1.1渐进式框架1.2 Vue的版本 二、VueAPI的风格三、Vue开发准备工作四、模板语法文本插值属性绑定条件渲染列表渲染key管理状态 四、事件处理定义事件事件参数事件修饰符 五、数组变化侦测 一、Vue框架 渐进式JavaScript框架&#xff0c;易学易用&#xff0c;性…