烫烫烫手的结构体大小计算来咯,很烫哦,慢慢消化。自定义类型(一)

emmm,在这炎热的夏天在宿舍吹着空调写着博客也是一件不错的事呢,今天就来来好好盘一下C语言中的自定义类型。

                 常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

                                                                      2024.03.29     小闭


目录

结构体的简单使用

 结构体的对齐规则

结构体的大小计算

结构体的简单使用

在 C 语言中,结构体(Structure)是一种用户自定义的数据类型,用于将不同类型的数据组合在一起形成一个复合的数据结构。结构体可以用来表示具有多个相关属性的对象,例如学生信息、员工信息、图书信息等。
 
以下是一个简单的 C 语言结构体代码示例:
 
 

struct Student {char name[50];int age;float marks;
};

这个结构体定义是正常的结构体命名,也有一些特殊的,如下:匿名结构体类型

struct
{int a;char b;float c;
}s;


 
 
上面代码中:我们定义了一个名为 Student 的结构体它包含了三个成员:一个长度为 50 的字符数组 name 用于存储学生的姓名,一个整数 age 用于存储学生的年龄,以及一个浮点数 marks 用于存储学生的成绩。
 
要使用结构体,可以创建结构体变量并访问其成员。例如:
 
 

struct Student student1;
strcpy(student1.name, "Alice"); // 复制字符串到 name 成员
student1.age = 20; // 给 age 成员赋值
student1.marks = 85.5; // 给 marks 成员赋值


 
 
通过” . “操作符,可以访问结构体变量的成员。在这个例子中,我们使用 student1.name 、 student1.age 和 student1.marks 来访问和操作结构体的各个成员。
 

注意:结构体还可以用于定义结构体数组,以及结构体指针等。它们提供了一种灵活的方式来组织和处理相关数据。其中数据结构中的链表和队列等就是用结构体指针完成。


 结构体的对齐规则
 

结构体的大小是结构体知识中是的小奥妙,还是直接写一段代码让大家感受一下,就可以更好的让人理解

int main()
{struct Test{char a;char b;int c;};struct Test T;printf("%d\n", sizeof(T));return 0;
}

 大家是否知道上面结构体的大小为何值,是不是觉得就是两个char和一个int加起来就是6个字节呢,相信初学者都这么认为,因为当初的我也是这样,那么正确答案是什么呢,答案却是8

 

至于为什么呢,这里我们就必须知道一个东西,那就是 ”结构体的内存对齐“。

何为结构体的内存

 那我们就需了解一个对齐规则,那么对齐规则是怎样的呢。

一、结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处

二、 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对⻬数 = 编译器默认的⼀个对齐数 与 该成员变量大小的较小值VS里的默认对齐数为8.

注意:有些编译器没有默认对齐数,此时成员的对齐数就是成员变量大小

三、结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对齐数中最大的)的 整数倍。

四、如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构 体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

 那么了解完后,我们该如何计算大小呢,那么我们现在就跟着对齐规则来,自己算一下上面代码结构体T大小为何为8吧。


结构体的大小计算

首先第一次见到对齐数很好奇,对齐数是什么?偏移量是什么?上面虽然已经解释了对齐数,但还是想知道如何实际用到对齐数来对结构体大小来进行计算。那么下来我将会把我的理解一步一步来解释。

首先我们先将一块用来储存此结构体的内存地址拿出来这里是一个字节代表一个单位,然后给这块内存从0开始标上序号,然后0数字即是0偏移量处。

int main()
{struct Test{char a;char b;int c;};struct Test T;printf("%d\n", sizeof(T));return 0;
}

然后我们再来看看这个结构体大小如何计算 

先我们把char a开始放在偏移量为0处如图红色部分,之后的成员从自身对齐数的整数倍处开始储存。

char类型的大小为1,与默认对齐数8,较小故此成员的对齐数为1
这里1是1的整数倍,所以放在从数字1处开始放char b,
如图黄色部分

这里如上int c的对齐数还是自身的大小,VS的默认对齐数是8,那么此时int c的自身大小为4,故取小的那么这里int c的对齐数就为4,往下找到最近的对齐数4的倍数处开始往下存放。如图绿色部分

完成成员的分布还没有结束,这里最后才是判断结构体大小的时候,按照上面规则:我们最后结构体大小是用全部成员中的最大的对齐数的整数倍,且是选最后一位成员后的整数倍数字,如这里变量a,b,c中c的对齐数最大为4,由于4处的位置已被分布需在最后位成员往后选4的倍数。即:8。那么此时结构体就是8了。


那么拿一题举例肯定是不准确的,我在拿一个例子来举例:

int main()
{struct R{int a;char b;int arr[2];}s;printf("%d\n", sizeof(s));return 0;
}

那么这里我就继续按照步骤来进行计算大小

int a 继续从偏移量为0处放,然后char b的对齐数为1,那么往后放在对齐数1的整数倍处即:数字4处,再然后int arr[2],这里注意我们不能把int arr[2]当作一个成员而应该当成两个int类型成员(这个要尤其注意),然后先将一个int放在对齐数4的整数倍处即:数字8处,然后继续将第二个元素也是放在对齐数4的整数倍处即:数字12处,。最后完成分布后选出成员中最大的对齐数即4,那么结构体大小为最后一位成员后面最大对齐数4的整数倍,即16.


然后再举一个结构体镶嵌的例子

int main()
{struct R{int a;char b;int arr[2];};struct Test{int a;struct R s;char b;short c;}t;printf("%d\n", sizeof(t));return 0;
}

这里要求的是结构体struct Test t 的大小,那么就看到R的成员,按照规则,将int a放在偏移量为0处,

然后就是镶嵌结构体struct R s;,其自身成员的最大对齐数为4,那么其对齐数为4,那找4的整数倍处即:数字4处。然后是char b对齐数为1,往后就是到数字20处,最后short c 对齐数为2,往后数字20处.完成分布我们找最大对齐数,为4那么其结构体大小为4的整数倍,最后取24为结构体大小。


讲到这里肯定是很疑惑为什么会存在内存对齐,对齐之后有些空间是浪费的。那么它存在就会有它存在的意义。简单来说就是:

结构体内存对齐是为了提高计算机的存储和访问效率。在现代计算机中,内存空间通常按照字节(byte)来划分,但各个硬件平台对存储空间的处理方式存在很大差异。
 
以32位的CPU为例,它一次能处理32bit(4字节)的数据,那么CPU就命令地址总线一次性读取4字节的数据,即每次的步长都为4字节,只对地址是4的整倍数的地址进行寻址,比如:0、4、8、100等。如果一个变量的地址刚好在一个寻址步长内,那么一次寻址就可以读取到该变量的值。但如果变量跨了步长存储,就需要寻址两次甚至多次,然后再进行拼接才能获取到变量的值,效率明显就低了。
 
为了避免这种情况,编译器会进行内存对齐,以保证变量的地址在一个寻址步长内,从而提高程序的运行效率。

总的来说:就是用空间换效率。


那么文章到这就结束了。

为今天努力的自己打个卡,留个痕迹吧

                                                                      2024.03.29     小闭

                                                    

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

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

相关文章

C++项目——集群聊天服务器项目(九)客户端异常退出业务

服务器端应检测到客户端是否异常退出,因此本节来实现客户端异常退出,项目流程见后文 一、客户端异常退出业务流程 (1)在业务模块定义处理客户端异常退出的函数 (2)集群聊天服务器项目(八)提到…

为什么在Python中总是使用【字典】这种类型呢?

你好,我是安然无虞。 文章目录 创建字典新增字典元素update 方法 删除字典元素pop 方法popitem 方法 查找字典元素in 和 in not 操作符get 方法thisdict[key] 修改字典元素遍历字典元素for循环遍历keys方法values方法items方法 合并字典字典中的key 字典常用接口汇…

网际协议 - IP

文章目录 目录 文章目录 前言 1 . 网际协议IP 1.1 网络层和数据链路层的关系 2. IP基础知识 2.1 什么是IP地址? 2.2 路由控制 3. IP地址基础知识 3.1 IP地址定义 3.2 IP地址组成 3.3 IP地址分类 3.4 子网掩码 IP地址分类导致浪费? 子网与子网掩码 3.5 CIDR与…

自己动手用ESP32手搓一个智能机器人:ESP32-CAM AI Robot

目录 介绍 硬件需求 软件需求 步骤 总结 源码下载 介绍 ESP32-CAM是一款集成了Wi-Fi和蓝牙功能的微控制器模块,同时还集成了摄像头接口,使其成为一个非常适合构建智能机器人的选择。在本项目中,我将向您展示如何使用ESP32-CAM模块构建…

数据运营分析-详解

一、指标与指标体系 指标体系就是业务逻辑的框架,也是思考业务逻辑的第一步 案例: 老板,我负责的用户活跃,主要考察每天启动产品的注册用户数量,整体来看,每月活跃保持7.3%的增长,是因为渠道团队的拉新活动带来很多新增注册用户,占每月活跃用户的40%,新一年会继续沿…

消息队列的七种经典应用场景

在笔者心中,消息队列,缓存,分库分表是高并发解决方案三剑客。 在职业生涯中,笔者曾经使用过 ActiveMQ 、RabbitMQ 、Kafka 、RocketMQ 这些知名的消息队列 。 这篇文章,笔者结合自己的真实经历,和大家分享…

Linux项目自动化构建工具-make/ makefile及其应用:多文件编写第一个linux程序:进度条(懒人学习必备博文!!!)

目录 1.前言--make/makefile的引入 2.快速上手make/makefile---自动化构建 3.关于依赖关系和依赖方法 4.自动化清理 为什么我们执行编译的时候,make一下就好,清理却要使用make clean? 5. make/makefile是如何知道当前目录下可执行文件是否为最新 6.文件…

express实现用户登录和注册接口

目录 1 创建数据库2 连接数据库3 集成ORM库4 创建业务逻辑5 创建路由7 测试接口总结 我们在编写后端接口的时候操作数据库是一种常见的功能需求,express本身并不提供直接操作数据库的能力,需要借助第三方库来操作数据库,本篇讲解一下软件开发…

【二叉树】Leetcode 543. 二叉树的直径【简单】

二叉树的直径 给你一棵二叉树的根节点,返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 示例1: 输入:root [1,2…

基于SpringBoot + Vue实现的在线装修管理系统设计与实现+毕业论文

介绍 系统包含用户、装修队、管理员三个角色 管理员: 管理员管理:管理其他管理员的账号和权限,确保系统管理的层次化和安全性。 装修队管理:审核装修队的资质,管理装修队的人员信息,监控工程进度&#xff…

elementUI this.$msgbox msgBox自定义 样式自定义 富文本

看这个效果是不是很炫?突出重点提示内容,对于用户交互相当的棒! 下来说说具体实现: let self = this const h = self.$createElement; this.$msgbox({title: null,message: h("p", {style: "margin-top:10px"}, [h("i", {class: "el-i…

命名空间【C++】(超详细)

文章目录 命名空间的概念命名空间的定义命名空间定义的位置作用域每一个命名空间都是一个独立的域作用域符:: 编译器找一个变量/函数等的定义,寻找域的顺序为什么要有命名空间?1.解决库与程序员定义的同名的重定义问题2.解决程序员…

【氮化镓】p-GaN栅极退化的温度和结构相关性

论文总结: 本文献深入研究了带有p-GaN栅极的正常关断型(normally-off)高电子迁移率晶体管(GaN-HEMTs)在恒定电压应力下的时序退化行为。通过直流特性分析和温度依赖性分析,研究了故障时间(TTF)与应力温度和器件几何结构的依赖性。结果显示,p…

FME学习之旅---day17

我们付出一些成本,时间的或者其他,最终总能收获一些什么。 【FME-HOW-TO系列】28 栅格邻域函数 RasterConvolver转换器说明: 接受包含栅格几何对象的输入要素,并在对所有波段应用卷积滤波 器后输出要素。 本人对栅格数据处理的较…

【2023】kafka在linux和docker安装(kafka-1)

目录💻 一、linux安装kafka1. 安装jdk2. 上传解压到/usr/local目录下3、使用kafka 二、docker安装kafka1. 下载2. 安装zookeeper3. 安装kafka 一、linux安装kafka 环境主机 mac m2、虚拟机Ubuntu22.04.4 1. 安装jdk yum install -y java-1.8.0-openjdk.x86_64下载k…

11-设计模式:Go常用设计模式概述

设计模式是啥呢?简单来说,就是将软件开发中需要重复性解决的编码场景,按最佳实践的方式抽象成一个模型,模型描述的解决方法就是设计模式。使用设计模式,可以使代码更易于理解,保证代码的重用性和可靠性。 …

【Entity Framework】EF中DbSet类详解

【Entity Framework】EF中DbSet类详解 文章目录 【Entity Framework】EF中DbSet类详解一、概述二、定义DbSet2.1 具有DbSet属性的DbContext2.2 具有 IDbSet 属性的 DbContext 2.3 具有 IDbSet 属性的 DbContext三、DbSet属性四、DbSet方法五、DbContext动态生成DbSet 一、概述 …

打工人神器! Raccoon 代码小浣熊

继这三个之后,今天又来了一个 [ Raccoon代码小浣熊 ] 核心精要与产品特点 全面支持多种编程语言和IDE:「代码小浣熊」支持超过90种主流编程语言,包括但不限于Python、Java、JavaScript、C、Go和SQL等。同时,它集成了市面上主流的…

Quiet-STaR:让语言模型在“说话”前思考

大型语言模型(llm)已经变得越来越复杂,能够根据各种提示和问题生成人类质量的文本。但是他们的推理能力让仍然是个问题,与人类不同LLM经常在推理中涉及的隐含步骤中挣扎,这回导致输出可能在事实上不正确或缺乏逻辑。 考虑以下场景:正在阅读一…

CTF题型 php://filter特殊编码绕过小汇总

CTF题型 php://filter特殊编码绕过小汇总 文章目录 CTF题型 php://filter特殊编码绕过小汇总特殊编码base64编码string过滤器iconv字符集 例题1.[Newstarctf 2023 week2 include]2.[Ctfshow web 117] php://filter 是一个伪协议,它允许你读取经过过滤器处理的数据流…