结构体 · 内存对齐

news2025/1/15 17:32:16

欢迎来到 Claffic 的博客 💞💞💞

前言:

在初识C语言中简单介绍了结构体,结构体可以理解为不同类型数据的集合体,但是你想过结构体的大小是如何计算的吗?看完这篇博客,你就能给自己答案了。

注:此博客包含进阶知识,建议学完C语言初阶知识再进行学习哦 ~  


1.请看题

#include<stdio.h>
struct Test
{
	int i;
	char c;
	double d;
};
int main()
{
	printf("%d\n", sizeof(struct Test));
	return 0;
}

问:程序输出多少? 

提示:编译环境VS2022,默认对齐数为8字节(什么意思? 留个悬念)

题目的意思就是要求我们计算 Test 这个结构体的大小

我们初步猜测:4(int 的大小)+ 1(char 的大小)+ 8(double 的大小)== 13 ;

是不是呢?

是    就没有这篇博客啦

接下来让我们看看结构体的对齐是怎么规定的:

2.结构体的对齐规则

1. 第一个成员 在与结构体变量 偏移量为0 的地址处;
2. 其他成员变量 要对齐到 对齐数 的 整数倍 的地址处;
    对齐数 = 编译器默认的一个对齐数 与 该成员大小的 较小值
3. 结构体 总大小 最大对齐数(每个成员变量都有一个对齐数)的 整数倍
4. 如果 嵌套 了结构体的情况,嵌套的结构体对齐到自己的 最大对齐数的整数倍 处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

规则读起来吃力,更不要说理解了

没关系,跟我捋一遍解题的步骤

跟我做完后再回来看上面的对齐规则,相信你会恍然大悟哒!

2.1画图准备

可以像我这样拷一份代码列一个表格补上默认对齐数

我用的是 windows11 自带的默认画图软件。

2.2对齐

按照数据上往下的顺序(i --> c -->  d)开始对齐,

先是第一个 int 类型的 i ,没啥顾虑的,直接从 偏移量 为 0的地方开始填充 ,填充 4 个字节(一个 int 类型大小)

 

这里对应 1. 第一个成员 在与结构体变量 偏移量为0 的地址处;

接下来是 char 类型的 c ,这里要多考虑了:

首先是 c 的大小 与 默认对齐数 (揭开悬念)的比较,取两者中的较小值1 ,作为改成员的对齐数;

接着是对齐,我们看到下一个空间的偏移量是 4 ,是 1 的整数倍 没错,可以放心填充。

这一步对应 2. 其他成员变量 要对齐到 对齐数 的 整数倍 的地址处;
                       对齐数 = 编译器默认的一个对齐数 与 该成员大小的 较小值

然后是 double 类型的 d ,同上:

8 与 8 比较,就取 8,作为该成员的对齐数

看下一个空间的偏移量是 5 ,不是 8 的整数倍,接着向下找,直到 8 ,开始填充:

最后就是结构体的总大小了:

很清楚,三个成员的最大对齐数是 8 ,那么总大小是 8 的整数倍

目前填充到了 15 ,无奈,15 不是 8 的整数倍,只能继续向下找 ,嗯 ,那个值是 16。

这里对应 3. 结构体 总大小 最大对齐数(每个成员变量都有一个对齐数)的 整数倍

所以这道题的正确答案是 16 

3.结构体嵌套

就着刚才解的题,再看下面这道:

#include<stdio.h>
struct Test
{
	int i;
	char c;
	double d;
};

struct Old
{
	int a;
	struct Test test;
	char b;
};

int main()
{
	printf("%d\n", sizeof(struct Old));
	
	return 0;
}

其实就是刚才的结构体 Test 被嵌套

这里就只提及结构体部分,其余的解法同上题

结构体 Test 中,最大的对齐数是 8,所以从 8 的整数倍开始填充,它的大小就是 16,填充 16 个字节。 

答案是 32 ,大家可以自行解决。

读到这里,建议再回首去看 4 条结构体的对齐规则,相信你会有明白的感觉 ~

4.内存对齐的原因:

不难发现,按照内存对齐,的却有内存被浪费了,但为什么还要按照这种规则呢?

根据参考资料,原因有两个方面。

1. 平台原因(移植原因):
    不是所有的硬件平台都能访问任意地址上的任意数据的;

    某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因:
    数据结构(尤其是栈)应该尽可能地在自然边界上对齐;
    原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需      要一次访问。

简单解释,一次内存访问是有固定大小的,大小 4 或 8,以一次访问 4 字节为例:

没有内存对齐:

就单看 int 类型的数据

访问两次才能拼凑出一个 int;

有内存对齐:

访问一次就可把 int 读取,且每次访问不交叉,干净利索

总的来说,这是一种 拿空间换时间 的做法,目前还是最优解。 

这样说能解答一些疑惑吧,但并不是标准的说法,不可钻牛角尖哦 ~


总结:

此博客详细讲解了结构体的内存对齐规则,内容比较干,建议多咀嚼,消化理解

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

关注我  不迷路!!!

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

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

相关文章

Linux 计算机网络 route 路由表、多网段与 bond 的故事

Linux 计算机网络 route 路由表、多网段与 bond 的故事 序 在之前的章节中&#xff0c;介绍了计算机网络的发展以及各种解析&#xff0c;在之中我们提到了每个主机设备都会维护一张自己的路由表&#xff0c;通过路由表来确定在不同网络之间&#xff0c;怎么将数据规划传输到各…

1988-2020年31省基尼系数数据

1、时间&#xff1a;1988-2020年 2、范围&#xff1a;31省 3、指标&#xff1a;包括省基尼系数年度数据&#xff0c;省城市和农村基尼系数年度 4、来源及计算方法说明附在文件内 5、指标说明&#xff1a; 基尼系数&#xff08;英文&#xff1a;Gini index、Gini Coefficie…

LeetCode 94. 二叉树的中序遍历

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛独家岛屿&#xff0c;本期将为大家揭晓LeetCode 94. 二叉树的中序遍历&#xff0c;做好准备了么&#xff0c;那么开始吧。 &#x1f332;&#x1f332;&#x1f434;&#x1f434; 一、题目名称 LeetC…

Mybatis获取参数

Mybatis获取参数 配置模板 mybatis获取参数值的两种方式 1、&{}&#xff1a; 字符串拼接 2、#{}&#xff1a; 占位符赋值 MyBatis获取参数值的各种情况&#xff1a; MyBatis获取参数值的各种情况&#xff1a; 1、mapper接口方法的参数为单个的字面量类型 可以通过&#xf…

双系统下 linux挂载window磁盘

如果想让linux访问window分区磁盘&#xff0c;呈只读状态&#xff0c;解决办法是bios取消window快速开机。永久挂载windows磁盘 https://blog.csdn.net/yuehenmiss/article/details/124737456 # 创建挂载目录 sudo mkdir /window # 挂载分区 sudo mount /dev/sda1 /window # 查…

产品经理必懂知识之计算机基础知识

作为产品经理&#xff0c;非常有必要了解一下计算机的发展历史&#xff0c;今天带大家一起&#xff0c;大概地了解一下计算机的基础知识&#xff0c;希望能够帮助到大家&#xff0c;框架如下&#xff1a; 一、计算机发展史 1.1计算机的诞生 1946年第一台电子计算机问世美国宾…

YOLOv8训练自己的数据集(超详细)

一、准备深度学习环境 本人的笔记本电脑系统是&#xff1a;Windows10 YOLO系列最新版本的YOLOv8已经发布了&#xff0c;详细介绍可以参考我前面写的博客&#xff0c;目前ultralytics已经发布了部分代码以及说明&#xff0c;可以在github上下载YOLOv8代码&#xff0c;代码文件夹…

一种车辆纵向控制切换算法设计思路

传统及主流的纵向控制切换算法&#xff1a; 例如《某避障控制策略研究》硕士论文&#xff1a; 在CarSim中设定节气门开度及制动踏板力为0&#xff0c;测得不同车速工况下车辆自然滑行的减速度。为了避免在控制过程中车辆驱动与制动切换的过于频繁&#xff0c;在其两侧设置了宽…

VUE_vue-cli 卸载不掉的问题解决

nodejs版本最好在v17以下&#xff0c;推荐使用v16.19.0 问题 由于项目需要旧版的 vue-cli &#xff0c;所以需要事先卸载新版本&#xff1b; 运行命令全局卸载&#xff1a; yarn global remove vue/cli// 查看当前版本确定是否卸载 vue --version结果还是旧版本&#xff0c;…

使用ResNet34实现CIFAR100数据集的训练

如果对你有用的话&#xff0c;希望能够点赞支持一下&#xff0c;这样我就能有更多的动力更新更多的学习笔记了。&#x1f604;&#x1f604; 使用ResNet进行CIFAR-10数据集进行测试&#xff0c;这里使用的是将CIFAR-10数据集的分辨率扩大到32X32&#xff0c;因为算力相关的…

5.8.1、TCP的连接建立

TCP 是面向连接的协议&#xff0c;它基于运输连接来传送 TCP 报文段。 TCP 运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。 TCP 运输连接有以下三个阶段 建立 TCP 连接&#xff1a;通过 “三报文握手” 建立 TCP 连接数据传送&#xff1a;也就是基于已建立的…

【PostgreSQL】手把手教学PostgreSQL

目录 1、PostgreSQL介绍 2、在ubuntu上通过命令安装 3、进入postgres用户 4、查看所有数据库 5、创建数据库 6、删除数据库 7、查看版本号&#xff08;注意&#xff1a;在sudo su - postgres下&#xff09; 8、远程连接 1、PostgreSQL介绍 官网&#xff1a;PostgreSQL: T…

SiC碳化硅功率器件测试哪些方面?碳化硅功率器件测试系统NSAT-2000

SiC碳化硅功率半导体器件具有耐压高、热稳定好、开关损耗低、功率密度高等特点&#xff0c;被广泛应用在电动汽车、风能发电、光伏发电等新能源领域。 近年来&#xff0c;全球半导体功率器件的制造环节以较快速度向我国转移。目前,我国已经成为全球最重要的半导体功率器件封测基…

wndows平台VS2019+OpenCV+cmake简单应用

wndows平台VS2019OpenCVcmake简单应用1.下载并解压文件2.结合人脸检测demo在vs中进行配置2.1 人脸检测代码2.2 在VS项目—属性中配置2.2.1 配置包含目录2.2.2 配置库目录2.2.3 配置链接器附加依赖项2.3 通过cmake进行配置与编译2.3.1 添加CMakeLists.txt文件2.3.2 cmake命令行执…

普中学习板准备工作

目录 1.1 ch341驱动安装 1. 目标板上的usb-串口模块插上 2. 按下目标板上的上电按钮 3. 打开ch341驱动程序&#xff0c;点击安装&#xff0c;等待结果 1.2 使用自动下载软件 1. 使用普中的自动下载软件 2. 串口号处选择安装好的驱动端口 3. 打开文件选择编译好的程序 …

2023 RealWorldCTF “Ferris proxy”逆向题分析(不算wp)

这题第二天才开始做&#xff0c;结果到比赛后4个小时才做出来&#xff0c;真是老了&#xff0c;不过也算有收获&#xff0c;对rust的程序更熟悉了~ client编译后的代码有41M&#xff0c;WTF 主函数入口 根据main函数找到两个入口 第二个函数很明显是主入口&#xff0c;不过…

数字图像相关系列笔记:DuoDIC

文章目录概述Algorithms and workflowStep 1: Stereo camera calibrationStep 2: Image cross-correlation (2D-DIC)Step 3: 3D reconstructionStep 4: Post processingValidation using a rigid body motion (RBM) testLimitations遗留问题参考资料附录概述 3D-DIC is a non-…

【C++、数据结构】AVL树 模拟实现

文章目录&#x1f4d6; 前言1. AVL树的概念1.1 二叉搜索树的缺点&#xff1a;1.2 AVL树的引入&#xff1a;1.2 AVL树的性质&#xff1a;2. AVL树的模拟实现2.1 AVL树结点的定义&#xff1a;2.2 AVL树的插入&#xff1a;&#xff08;重点&#xff09;2.2.1 插入结点后平衡因子的…

【前端】Vue项目:旅游App-(14)home+search:搜索按钮及其路由跳转、分组数据的网络请求request、数据存储store和动态显示

文章目录目标过程与代码搜索部分&#xff1a;搜索按钮点击搜索按钮路由跳转并传数据search页面隐藏TabBar分类部分&#xff1a;数据请求&#xff1a;request、store显示数据分类的样式总代码修改或添加的文件common.cssrouter的index.jsservice的home.jsstore的home.jshome-cat…

Windows系统下 pyinstaller将python文件打包成可执行文件exe的方法

使用环境为Windows10系统&#xff08;64&#xff09;&#xff0c;Python版本为3.11.1。 1.将pip加入环境变量 &#xff08;1&#xff09;右击此电脑点击"属性"&#xff0c;点击高级系统设置&#xff0c; &#xff08;2&#xff09;选择最下面的环境变量&#xff1b…