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

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     小闭

                                                    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【一】DDR3基础知识与IMG IP

【一】DDR3基础知识与IMG IP 一、DDR3的基本知识 1、DDR3全称为第三代双倍速率同步动态随机存储器 特点:掉电无法保存数据,需要周期性的刷新;时钟上升沿和下降沿都在传输数据;突发传输,突发长度burtst length一般为…

【C++庖丁解牛】基于红黑树实现的两种常用的关联容器map和set以及multimap

🍁你好,我是 RO-BERRY 📗 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 目录 1. 关联式容器2. 键值对3…

最短路径——Floyd算法、Dijkstra算法(未完...)

这里写目录标题 例题引入: 路径——蓝桥2021省赛题目分析题解!!!求最短路径问题!!!应用场景图的基础Floyd算法Acwing-843.有边数限制的最短路简单的思路讲解 Dijkstra算法 例题引入:…

鸿蒙应用开发与鸿蒙系统开发哪个更有前景?

随后迎来了不少互联网公司与华为鸿蒙原生应用达成了合作,像我们常见的阿里、京东、小红书、得物……等公司,还有一些银行也都与华为鸿蒙达成了合作。使得一时之间市场紧缺鸿蒙开发人才,不少公司不惜重金争抢人才。 据智联招聘的最新数据显示…

最强的营销团队,这样打造!

在瞬息万变的商业环境中,构建无可挑剔的营销团队结构的重要性毋庸置疑。营销团队的力量不仅在于其成员的个人才能,还在于这些才能如何有效地协调在一起。建立完美的营销团队结构类似于拼图。每块拼图都代表了独特的技能和视角,如果放置得当&a…

未来5年|个人电脑“变”AI PC

随着生成式AI热潮达到白热化阶段,笔记本电脑市场正面临一场范式转变。根据Tech Insights预测数据,到2029年,配备专用AI加速芯片(即NPU)的AI赋能笔记本电脑将在整个笔记本市场占据主导地位,占比高达95%&…

【MySQL】事务是什么?事务的特性又是什么?

文章目录 ✍事务是什么?✍事务的特性(四个)✍事务并发时出现的问题✍事务的隔离性 ✍事务是什么? 事务是由一个或多个SQL语句构成的,在事务中,这些的SQL不可分割,是一个整体,整个事…

牛客NC30 缺失的第一个正整数【simple map Java,Go,PHP】

题目 题目链接: https://www.nowcoder.com/practice/50ec6a5b0e4e45348544348278cdcee5 核心 Map参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可…

web前端之罗盘时钟、不一样的补零方式、LED字体、padStart

MENU 效果图htmlJavaScriptstyle 效果图 html <div class"clock"><div class"second-box"></div><div class"minute-box"></div><div class"hour-box"></div><div class"day-box&…

HarmonyOS 应用开发之Stage模型启动FA模型PageAbility

本小节介绍Stage模型的两种应用组件如何启动FA模型的PageAbility组件。 UIAbility启动PageAbility UIAbility启动PageAbility和UIAbility启动UIAbility的方式完全相同。 说明&#xff1a; 需注意FA模型中abilityName由bundleName AbilityName组成&#xff0c;具体见示例。 i…

蓝桥杯第十三届电子类单片机组程序设计

目录 前言 单片机资源数据包_2023 一、第十三届比赛省赛 1.比赛题目 2.赛题解读 二、部分功能实现 1.继电器的开启与关闭 2.长按切换显示状态功能的实现 3.对于温度传感器小数部分的处理 4.其他处理 1&#xff09;关于数码管显示小数的处理 2&#xff09;关于5s后继…

vue3+ts+elementplus写一个登录页面教程

文章目录 前言1. 安装 Vue CLI 和 TypeScript 支持2. 创建登录组件 文章重点内容 前言 前期准备步骤&#xff1a; 创建一个使用 Vue 3 和 TypeScript 的登录页面涉及到多个步骤。以下是一个基本的教程&#xff0c;帮助你从头开始构建这样一个页面&#xff1a; 1. 安装 Vue CL…

Ollama部署在线ai聊天

概述&#xff1a;虽然ollama在Windows方面还有很多bug&#xff0c;但不妨碍它在ai领域上面的成就 第一步&#xff1a;安装Ollama 官网&#xff1a;Download Ollama on Windows 下载安装即可。说明一下ollama的安装位置只能是c盘&#xff0c;好像改不了&#xff0c;但是数据模…

算法学习——LeetCode力扣动态规划篇8

算法学习——LeetCode力扣动态规划篇8 300. 最长递增子序列 300. 最长递增子序列 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删…

FA模型切换Stage模型之module的切换

从FA模型切换到Stage模型时&#xff0c;开发者需要将config.json文件module标签下的配置迁移到module.json5配置文件module标签下&#xff0c;具体差异见下列表格。 表1 FA模型module标签与Stage模型module标签差异对比 表2 FA模型metaData和Stage中metadata对比 表3 FA模型me…

【UI框架】——保姆式使用教程

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

深度学习500问——Chapter05: 卷积神经网络(CNN)(2)

文章目录 5.6 有哪些池化方法 5.7 1x1卷积作用 5.8 卷积层和池化层有什么区别 5.9 卷积核是否一定越大越好 5.10 每层卷积是否只能用一种尺寸的卷积核 5.11 怎样才能减少卷积层参数量 5.12 在进行卷积操作时&#xff0c;必须同时考虑通道和区域吗 5.13 采用宽卷积的好处有什么 …

多线程JUC 第2季 synchornized和Lock锁(重入,公平)

一 锁 1.1 锁的介绍 synchronized&#xff0c;和lock锁都是一种悲观锁。悲观锁适用于写多场景&#xff0c;乐观锁适用于读多场景&#xff0c;实现策略有&#xff1a;版本号和cas自旋算法。 1.2 类锁和对象锁的使用场景 1.3 任何对象都有一把锁 之所以任何一个对象都有把锁…

html第二次作业

骨架 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, initi…

PyTorch深度学习快速入门(小土堆)

文章目录 16. 神经网络的基本骨架17.卷积操作18.卷积层 16. 神经网络的基本骨架 forward: import torch from torch import nnclass Tudui(nn.Module):def __init__(self):super().__init__()def forward(self,input):outputinput1return output#创建Tudui的实例对象 tuduiTu…