【C++】内存对齐

news2024/10/2 10:44:59

本篇文章介绍C++中的内存对齐,后续介绍C的union和C++的variant的时候,需要用到这部分的知识。

占用内存

先回忆下C++各个数据类型占用的内存大小:

  1. int:所占内存大小:4byte = 32bit;
  2. char:所占内存大小:1byte = 8bit;

还有其他的数据类型,但是今天就只用这两个。
我们写个结构体:

struct s{
    int x;
    char y;
};

它占用多少byte的内存呢?并不是4+1=5,而是4+4=8.

int main()
{
    printf("%d\n",sizeof(s));  // 输出8
    return 0;
}

结果

分析内存

处理器并不是按字节块来存取内存的。它一般会以2字节,4字节,8字节,16字节甚至32字节为单位来存取内存.我们将上述这些存取单位称为内存存取粒度.写代码的人一般会觉得所有数据结构都会像数组一样有随机存取的特性,变量之间是紧挨着的,但是对于不同类型的变量来说,从内存向寄存器转移数据的过程并不总是顺利的。

以下图片来自https://blog.csdn.net/dxpqxb/article/details/90485917,我懒得画图了,就直接用现成的了。

现在有4byte的数据存放在内存中,他们的地址如下:

数据首地址末地址
A03
B14

假设内存存取粒度是1byte,取A和B都只需要取4次即可
1byte
当内存存取粒度是2byte时,A只需要取两次,分别为0和1、2和3;但是B从1开始,取2次取到了1、2和3,第4byte的数据还没取到,因此还需要取一次,总共取了3次。同时,还要把无用的第0byte和第5byte数据丢掉。
2byte
当内存存取粒度是4byte时,同样的道理,A只需要取1次4byte,B则需要取2次,并丢弃第0,第5-7byte的数据。
4byte
现在有了内存对齐的,int类型数据只能存放在按照对齐规则的内存中,比如说0地址开始的内存。那么现在该处理器在取数据时一次性就能将数据读出来了,而且不需要做额外的操作,提高了效率。
内存对齐

内存对齐

内存对齐的一个原则就是,不要让变量跨内存存取粒度存储。

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。gcc中默认#pragma pack(4),可以通过预编译命令#pragma pack(n),n = 1,2,4,8,16来改变这一系数。

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

了解了上面的概念后,我们现在可以来看看内存对齐需要遵循的规则:

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

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

我们看下面三个结构体:

#include <stdio.h>
struct x1
{
    int i;
    char c1;
    char c2;
};

struct x2
{
    char c1;
    int i;
    char c2;
};

struct x3
{
    char c1;
    char c2;
    int i;
};

int main()
{
    printf("%d\n", sizeof(x1)); 
    printf("%d\n", sizeof(x2)); 
    printf("%d\n", sizeof(x3)); 
    return 0;
}

有效对齐值为4

不考虑结构体本身对外的偏移量,我们以x1为例,i的大小是4,有效对齐值也是4,只要保证偏移量为4的整数倍就行,因此i占用0,1,2,3;c1和c2的大小都是1,有效对齐值为4,只要保证偏移量为1的整数倍即可,因此占用4和5;结构体本身需要对外对齐,必须是4的整数倍,因此将6和7填充上。其他两个结构体也是一样的分析方式。

现在我们改变有效对齐值为2,输出结果如下:
有效对齐值为2
依然以x1为例,i的大小为4,有效对齐值是2,只要保证偏移量为2的整数倍就行,因此i占用0,1,2,3;c1和c2的大小都是1,有效对齐值为2,只要保证偏移量为1的整数倍即可,因此占用4和5;结构体本身需要对外对齐,必须是2的整数倍,无需填充。

其他

C++11

对齐的英文是alighment,C++11引入了一个函数alignof,可以直接获取类型T的内存对齐要求,也就是最大的成员大小与有效对齐值中较小那个。比如当有效对齐值为4时,上面3个结构体的alignof结果都是4.

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

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

相关文章

单机部署Rancher

上次已经安装完毕了k8s了&#xff0c;但是想要界面化的管理&#xff0c;离不开界面工具&#xff0c;首推就是rancher&#xff0c;本文介绍安装rancher的安装&#xff0c;也可以将之前安装的k8s管理起来。 已经安装完毕docker和docker-ce的可以直接从第三部分开始。 一、基础准…

如何充值GPT会员账号?

详情点击链接&#xff1a;如何充值GPT会员账号&#xff1f; 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Claude2二定制自己的…

五、HTML 标题

在 HTML 文档中&#xff0c;标题很重要。 一、HTML 标题 标题&#xff08;Heading&#xff09;是通过 <h1> - <h6> 标签进行定义的。<h1> 定义最大的标题。 <h6> 定义最小的标题。 <h1>这是一个标题。</h1> <h2>这是一个标题。&l…

python 模块搜索路径

前言 当我们import os的时候&#xff0c;Python解释器去哪找os模块呢&#xff1f;如果多处都有os模块&#xff0c;选择哪个os模块呢&#xff1f; 去哪找os模块&#xff1f; Python解释器不是很神奇&#xff0c;它会从以下2个地方找os模块 1、内置模块 sys.builtin_module_nam…

软件测试|深入解析Docker Run命令:创建和启动容器的完全指南

简介 Docker是一种流行的容器化平台&#xff0c;用于构建、分发和运行应用程序。其中一个最基本且重要的Docker命令是docker run&#xff0c;用于创建和启动容器。本文将详细解析docker run命令的用途、参数和示例&#xff0c;帮助您全面掌握创建和启动容器的过程。 docker r…

竞赛保研 基于深度学习的中文情感分类 - 卷积神经网络 情感分类 情感分析 情感识别 评论情感分类

文章目录 1 前言2 情感文本分类2.1 参考论文2.2 输入层2.3 第一层卷积层&#xff1a;2.4 池化层&#xff1a;2.5 全连接softmax层&#xff1a;2.6 训练方案 3 实现3.1 sentence部分3.2 filters部分3.3 featuremaps部分3.4 1max部分3.5 concat1max部分3.6 关键代码 4 实现效果4.…

面试官:说说HashMap和HashTable的区别

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一波电子书籍资料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虚拟机》&#xff0c;《重构改善既有代码设计》&#xff0c;《MySQL高性能-第3版》&…

窗体控件(表格和控制器)

DataGridView 控件 DataGridView控件是C#中的一个Windows Forms控件&#xff0c;用于在应用程序中显示和编辑表格形式的数据。 先拖出四个label控件和四个TextBox控件和一个ComboBox和一个Button按钮&#xff0c;下面是一个DataGridView控件 准备一个Student类 namespace _窗…

html5中各标签的语法格式总结以及属性值说明

有关闭标签的元素 a元素 <a href"" target"" title""></a>表格相关元素 table元素&#xff1a;表格标签caption元素&#xff1a;表头thead元素tbody元素&#xff1a;表格主体元素tfoot元素th元素tr元素&#xff1a;行标签td元素&…

vue2 消息弹框

父页面 <template><div style"margin-top: 20px"><div class"nav-style msg-style"><el-badge :value"value" :max"99" class"num" v-if"value > 0"><i class"el-icon-bell&…

虾皮怎么选品:虾皮(Shopee)跨境电商业务成功的关键步骤

在虾皮&#xff08;Shopee&#xff09;平台上进行跨境电商业务&#xff0c;选品是至关重要的一环。有效的选品策略可以帮助卖家更好地了解市场需求&#xff0c;提高销售业绩和客户满意度。以下是一些成功的选品策略&#xff0c;可以帮助卖家在虾皮平台上取得更好的业务成绩。 先…

Unix操作系统的前世今生

Unix是一种多用户、多任务操作系统&#xff0c;最初由AT&T贝尔实验室的肯汤普逊&#xff08;Ken Thompson&#xff09;和丹尼斯里奇&#xff08;Dennis Ritchie&#xff09;等人开发于上世纪70年代初。它被设计成一种通用的操作系统&#xff0c;支持跨多种硬件平台&#xf…

Linux磁盘、网络信息监控、df命令、iostat命令、sar命令

通过df命令可以查看磁盘的使用情况 形式&#xff1a;df [-h] -h&#xff1a;以更加人性化的单位显示 通过iostat命令查看CPU、磁盘的相关信息 形式&#xff1a;iosrtat [-x] [num1] [num2] -x&#xff1a;显示更多信息 num1&#xff1a;刷新间隔 num2&#xff1a;刷新次数…

UAV | 多算法在多场景下的无人机路径规划(Matlab)

近年来&#xff0c;无人机(unmanned aerial vehicle&#xff0c;UAV)由于其灵活度高、机动性强、安全风险系数小、成本低等特点&#xff0c;被广泛应用于搜索巡逻、侦察监视、抢险救灾、物流配送、电力巡检、农业灌溉等军用或民用任务。路径规划是无人机执行任务的关键&#xf…

我的NPI项目之设备系统启动(二) -- 系统启动阶段和分区的区别

系统启动的就几大阶段&#xff1a; 基于高通平台的Android OS启动过程&#xff0c;简单的说&#xff0c;可以分为一下几个部分&#xff1a; 之前一个比较老的平台大概是这样&#xff1a; 现在比较新的5G平台&#xff1a; 差别在这里&#xff0c;重点了解一下新平台的情况。xb…

Java BIO、NIO、AIO、Netty知识详解(值得珍藏)

1. 什么是IO Java中I/O是以流为基础进行数据的输入输出的&#xff0c;所有数据被串行化(所谓串行化就是数据要按顺序进行输入输出)写入输出流。简单来说就是java通过io流方式和外部设备进行交互。 在Java类库中&#xff0c;IO部分的内容是很庞大的&#xff0c;因为它涉及的领…

深度学习 Day24——J3-1DenseNet算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 文章目录 前言1 我的环境2 pytorch实现DenseNet算法2.1 前期准备2.1.1 引入库2.1.2 设…

静态网页设计——宠物狗狗网(HTML+CSS+JavaScript)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a; https://www.bilibili.com/video/BV1nk4y1X74M/?vd_source5f425e0074a7f92921f53ab87712357b 使用技术&#xff1a;HTMLCSSJS&#xff08;…

【Java EE初阶六】多线程案例(单例模式)

1. 单例模式 单例模式是一种设计模式&#xff0c;设计模式是我们必须要掌握的一个技能&#xff1b; 1.1 关于框架和设计模式 设计模式是软性的规定&#xff0c;且框架是硬性的规定&#xff0c;这些都是技术大佬已经设计好的&#xff1b; 一般来说设计模式有很多种&#xff0c;…

ROS-arbotix安装

方式一&#xff1a;命令行输入&#xff1a; sudo apt-get install ros-melodic-arbotix如果ROS为其他版本&#xff0c;可将melodic替换为对应版本。 方式二&#xff1a; 先从 github 下载源码&#xff0c;然后调用 catkin_make 编译 git clone https://github.com/vanadiumla…