Day_16 结构体

news2024/11/25 18:58:56

目录

1.结构体

1.1结构体类型的声明

1.结构体的基础知识

2.结构的声明

3.特殊的声明 

1.2结构的自引用

1.3结构体变量的定义和初始化

1.4结构体内存对齐

1.怎么对齐的

2.为什么要对齐 

3.修改默认对齐数

1.5结构体传参

1.传值调用

2.传地址调用 

3.结论

1.6结构体实现位段(位段的填充&可移植性)

1.什么是位段

2.位段的内存分配 

3.位段的跨平台问题 

2.枚举

2.1枚举类型的定义

2.2枚举的优点

3.联合(共用体)

3.1联合类型的定义

3.2联合的特点

3.3联合大小的计算


1.结构体

1.1结构体类型的声明

1.结构体的基础知识

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量

2.结构的声明

struct tag
{
	member - list;
}variable - list;
  • struct是结构体关键字,不能省略
  • tag是名字,可以自己设定 

假设要描述一个学生Student

struct Student
{
	char name[20];
	int age;
	char sex[5];
	float score;
}s1,s2,s3;//s1,s2,s3是三个结构体变量
int main()
{
	struct Student s4, s5, s6;//s4,s5,s6也是三个结构体变量
	return 0;
}

 区别在于:

  • s1,s2,s3是全局变量
  • s4,s5,s6是局部变量

3.特殊的声明 

在声明结构体的时候,可以不完全声明

(省略tag标签,在末尾分号前定义一个变量,只可以使用一次,称为匿名结构体类型)

1.2结构的自引用

我们先有一个数据结构的概念:

数据结构描述的是数据在内存中的存储和组织结构

在结构中包含一个类型为该结构本身的成员

正确的自引用方式:

struct Node
{
	int data;
	struct Node* next;
};

 结构体里包含一个同类型的结构体是不行的

但是结构体里包含一个同类型的结构体指针是可以的

这个时候匿名就是不行的,需要一个完整的结构体类型

1.3结构体变量的定义和初始化

有了结构体类型,那如何定义变量就很简单了

struct Point
{
	int x;
	int y;
}p1;            //声明类型的同时定义变量p1
struct Point p2 = { 4,5 };//定义结构体变量p2

//初始化:定义变量的同时赋初值
struct Ponit p3;

这几种定义方法都是可行的

对于复杂结构体可以用大括号初始化

struct Stu
{
	char name[20];
	int age;
};

int main()
{
	struct Stu s = { "张三",20 };
	return 0;
}

结构体也可以嵌套初始化 

1.4结构体内存对齐

我们先看一个例子:

我们计算一下S1和S2的大小,他们定义的时候成员变量的顺序不同

这里存在一个结构体内存对齐的问题

我们介绍一个知识:

offsetof  //这是一个宏,可以直接使用

//计算结构体成员相较于起始位置的偏移量的

1.怎么对齐的

结构体的对齐规则:

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

对齐数=编译器默认的一个对齐数 与 该成员大小的较小值

  • vs中默认的值为8
  • Linux中没有默认对齐数,对齐数就是成员自身的大小

下面这篇文章详细的解释了结构体内存对齐规则

C语言--结构体内存对齐规则_结构体对齐原则-CSDN博客

2.为什么要对齐 

大部分的参考资料都是这样解释的:

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

总的来说:

结构体的内存对齐是拿空间来换取时间的做法

在设计结构体的时候,我们既要满足对齐,又要节省空间:

就需要让占用空间小的成员尽量集中在一起

3.修改默认对齐数

#pragma pack(N) 

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

1.5结构体传参

1.传值调用

2.传地址调用 

函数传参的时候,参数是需要压栈的,会有时间和空间上的系统开销

如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,会导致性能的下降 

3.结论

结构体传参的时候,尽量传结构体的地址

1.6结构体实现位段(位段的填充&可移植性)

1.什么是位段

结构体下来就得了解一下结构体实现位段的能力

位段的出现就是为了节省空间

位段的声明和结构是类似的,有两个不同:

  1. 位段的成员必须是int,unsigned int 或 signed int 也可以是char类型
  2. 位段的成员名后面有一个冒号和一个数字

举个例子

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

这就是一个位段 

位段的位指的是二进制位

2.位段的内存分配 

  1. 位段的成员可以是int 、unsigned int 、signed int 或者是char(属于整型家族)类型
  2. 位段的空间上是按照需要以4个字节(int)或者一个字节(char)的方式来开辟的
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植性的程序应该避免使用位段

3.位段的跨平台问题 

  1. int位段被当成有符号数还是无符号数是不确定的
  2. 位段中最大位的数目不能确定(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义
  4. 当一个结构体包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的

跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在 

2.枚举

枚举顾名思义就是一一列举

把可能的取值一一列举

2.1枚举类型的定义

枚举关键字是enum

enum Sex
{
	//枚举的可能取值
	MALE,//枚举常量
	FEMALE,
	SECRET
};

枚举常量的取值是从0开始的

在主函数中,我们用枚举常量的可能取值给他赋值,比如:

2.2枚举的优点

为什么使用枚举?

我们可以使用#define定义常量,为什么非要使用枚举?

枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨
  3. 便于调试
  4. 使用方便,一次可以定义多个常量

3.联合(共用体)

3.1联合类型的定义

联合也是一种特殊的自定义类型

这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)

联合体关键字是union

union Un
{
	char c;
	int i;
};

联合体的成员,在同一时间只能使用一个 

3.2联合的特点

联合的成员是公用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的成员)

3.3联合大小的计算

联合的大小至少是最大成员的大小

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

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

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

相关文章

SOLIDWORKS二次开发

SOLIDWORKS是一套三维设计软件, 采用特征建模、变量化驱动可方便地实现三维建模、装配和生成工程图。SOLIDWORKS软件本身所具有的交互方式,可以使用户对已生成模型的尺寸、几何轮廓和相互约束关系随时进行修改, 而不需要编程。SOLIDWORKS软件本身的方程式可以实现简…

订阅《复现SCI文章系列教程》

写在前面 《小杜生信笔记》准备开启新的订阅专栏**《复现期刊文章系列教程》,本专栏小杜会寻找一些自己感兴趣的文章进行复现(不说百分之百的复现,但是也会百分之八十进行复现)。本期刊的教程代码会全部进行公开(通过订…

uniapp项目实践总结(二十三)网页和小程序应用打包教程

导语:当你的应用程序开发完成后,在发布到互联网之前,需要进行打包操作,包括网页端、小程序端的打包。 目录 准备工作网页打包小程序打包 准备工作 在打包之前,请保证你的 uniapp 应用程序编译到网页、小程序是可以正…

40亿美元!ChatGPT竞争对手Anthropic,再获巨额融资

9月25日下午,生成式AI平台Anthropic在官网宣布,获得亚马逊(Amazon)40亿美元(约292亿元)投资,成为全球生成式AI赛道最高融资之一。 本轮过后,Anthropic的总融资额度达到56亿美元&…

数据结构--堆排序

目录 堆的定义 建立初始化堆的步骤 建立大根堆的代码 大根堆排序的代码 算法效率分析 稳定性 堆的定义 回忆 基于选择排序的特性:选取关键字最小(或者最大)的元素放入到序列里面,知道了大堆和小堆概念,所以将…

解决电脑桌面软件图标变白的问题

文章目录 前言一、软件图标变白的原因二、解决方法1、显示隐藏项目2、清除图标缓存 前言 桌面软件太多了,导致有些杂乱,换了个显示器后,想着将桌面的软件分类,将其放到不同的目录下,结果有些软件放入文件夹后图标变成…

【【萌新的FPGA学习之触摸屏控制LED实验】】

萌新的FPGA学习之触摸屏控制LED实验 触摸屏控制LED实验 触摸按键主要可分为四大类:电阻式、电容式、红外感应式以及表面声波式。根据其属性的不同,每 种触摸按键都有其合适的使用领域。 电阻式触摸按键由多块导电薄膜按照按键的位置印制而成&#xff0c…

链表(单链表、双链表)

前言:链表是算法中比较难理解的部分,本博客记录单链表、双链表学习,理解节点和指针的使用,主要内容包括:使用python创建链表、实现链表常见的操作。 目录 单链表 双链表 单链表 引入链表的背景: 先来看…

Goby 漏洞发布|泛微 E-office flow_xml.php 文件 SORT_ID 参数 SQL 注入漏洞

漏洞名称:泛微 E-office flow_xml.php 文件 SORT_ID 参数 SQL 注入漏洞 English Name: Weaver E-office flow_xml.php file SORT_ID parameter SQL injection vulnerability CVSS core:7.8 影响资产数: 21632 漏洞描述: 泛微…

idea创建同级项目-纠结是SB

idea创建同级项目-纠结是SB 创建方法:

线性约束最小方差准则(LCMV)波束形成算法仿真

常规波束形成仅能使得主波束对准目标方向,从而在噪声环境下检测到目标,但无法对复杂多变的干扰做出响应,所以不能称之为真正意义上的自适应滤波。自适应阵列处理指的是采用自适应算法对空间阵列接收的混合信号进行处理,又可称为自…

【Element-UI】实现动态树、数据表格及分页效果

一、导言 1、引言 在现代软件开发中,动态树、数据表格以及分页效果成为了许多应用的核心需求。随着业务规模和复杂性的增加,我们往往需要展示大量的层级结构数据,并且实现交互性强且高效的操作。 动态树提供了一种组织结构清晰、可伸缩的展示…

提取PDF数据:Documents for PDF ( GcPdf )

在当今数据驱动的世界中,从 PDF 文档中无缝提取结构化表格数据已成为开发人员的一项关键任务。借助GrapeCity Documents for PDF ( GcPdf ),您可以使用 C# 以编程方式轻松解锁这些 PDF 中隐藏的信息宝藏。 考虑一下 PDF(最常用的文档格式之一…

4代码工程结构

产品代码都给你看了,可别再说不会DDD(四):代码工程结构 # 这是一个讲解DDD落地的文章系列,作者是《实现领域驱动设计》的译者滕云。本文章系列以一个真实的并已成功上线的软件项目——码如云(https://www.…

接口自动化测试框架【reudom】

reudom Automated testing framework based on requests and unittest interface. 基于 Unittest 和 Requests 的 接口自动化测试框架 介绍 基于Unittest/Requests的接口自动化测试库 提供脚手架,快速生成接口自动化测试项目。自动生成HTML测试报告。支持用例参数…

「网页开发|前端开发|Vue」09 Vue状态管理Vuex:让页面根据用户登录状态渲染不同内容

本文主要介绍如何通过Vue的状态管理框架Vuex来管理一些被不同组件或不同页面共同使用的数据,然后展示如何通过状态管理用户信息,并且在具体页面获取用户信息,并且根据用户信息的不同展示不同的页面内容。 文章目录 本系列前文传送门一、场景…

手把手教你,细说向开源项目递交代码的流程

系列文章目录 手把手教你安装Git,萌新迈向专业的必备一步 GIT命令只会抄却不理解?看完原理才能事半功倍! 常用GIT命令详解,手把手让你登堂入室 GIT实战篇,教你如何使用GIT可视化工具 GIT使用需知,哪些操作…

面试必杀技:Jmeter性能测试攻略大全(第三弹)(脚本开发)

今天是最后一章哦,主要是讲jmeter性能测试脚本相关的。原创不易,点个赞意思一下呗! 一. 脚本开发方式大纲 1、badboy进行录制和导出 badboy下载地址: 链接:https://pan.baidu.com/s/18Po3RssrBRSnn_-xsHop1g 提取码&#xff1…

协程切换的三种底层实现方式

1.setjmp/longjmp setjmp 和 longjmp 是C语言中用于实现基本的协程的底层函数。它们允许在一个函数的执行过程中保存当前的执行状态(包括寄存器和栈信息),然后在之后的某个时间点恢复到这个状态,从而实现函数的非局部跳转。 这两…

OpenGl材质

在现实世界里,每个物体会对光产生不同的反应。比如,钢制物体看起来通常会比陶土花瓶更闪闪发光,一个木头箱子也不会与一个钢制箱子反射同样程度的光。有些物体反射光的时候不会有太多的散射(Scatter),因而产生较小的高光点&#x…