当前位置: 首页 > news >正文

自定义类型——结构体

目录:

一、结构体类型

        1.1结构体的声明

        1.2 结构体的特殊声明

二、结构体内存对齐

三、结构体传参

四、结构体实现位段

        4.1 什么是位段

        4.2 位段的内存分配

        4.3 位段跨平台和注意事项


正文开始:

一、结构体类型

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

struct定义的是结构体类型!类型!要创建结构体变量,要用结构体类型创建

例如:描述一个学生,有姓名、年龄、性别、学号,把这些放进用struct定义的结构体类型中就称为结构体的成员。

Stu是结构体类型名,结构体内只定义成员变量不赋值,结构体结尾一定要有逗号。

1.1 结构体类型的声明

一般情况下对应结构体成员创建的顺序进行初始化

如果我偏就不按顺序呢?

可以,前面加点结构体成员名再赋值

1.2 结构体的特殊声明

(1)匿名结构体:

结构体可以不完全声明,创建时不写结构体标签(名字),也就为匿名结构体。就像网上有很多网友发言,但是不显示他们真实姓名,以匿名形式发言。

匿名结构体只能使用一次,非特定需要最好不用。

s:表示用结构体类型直接创建一个结构体变量s,可直接用s点成员名赋值,匿名结构体s只能被使用一次

(2)typedef 重命名结构体

要创建结构体变量,每次总要写类型名struct Node创建,当结构体类型名过长可以typedef重命名结构体类型名为Node。下次可以直接拿Node代替struct Node创建结构体变量。

例如:一个叫张三的同学,平时大家都叫他小张,这两者指的都是同一个人。

(3)结构体的自引用

在结构体⾃引⽤使⽤的过程中,夹杂了 typedef 对结构体类型重命名,也容易引⼊问题,看看
下⾯的代码,可⾏吗?

答案是:不行!因为Node是对结构体类型重命名产⽣的,但是在匿名结构体内部提前使⽤Node类型来创建成员变量,这是不⾏的。

解决方案如下:

二、结构体内存对齐

点击下方链接可进入我之前写的博客,学习内存对齐知识。

结构体内存对齐-CSDN博客

三、结构体传参

(1)传值调用

先创建一个结构体变量s,初始化,定义个函数print1打印结构体内每个成员数据。

因为打印结构体并不改变原始结构体的数据,所以传值过去可以

(2)传址调用

不改变数据用传值调用可以,那我用传址可以吗?

可以的,通过指针访问结构体的每个成员

打印结构体通过传值和传址都行,哪个好呢?

传值:

形参是实参的一份临时拷贝。我们定义的结构体中包含了一个大小为1000的数组,内存要为创建的结构体开辟空间,若传值实参占用内存有多大,形参也同样要拷贝同等大小的空间存储结构体内数据,而内存空间是有限的如果这样会占用很多内存空间造成空间浪费

传址:

不管实参结构体内存开辟多大空间,我始终传过去的是地址,是地址就用指针接收,一个指针开辟的空间根据当前环境的不同占用4或8个字节,在内存上比传值好得多。

总结:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递⼀个结构体对象的时候,结构体过⼤,参数压栈的的系统开销⽐较⼤,会导致性能的下降。 所以结构体在调用时采用传址调用。

四、结构体实现位段

4.1 什么是位段

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

(1)位段的成员必须是 int、unsigned int 或 signed int ,在C99中位段成员的类型也可以选择其他类型。

(2)位段的成员名后面有一个冒号和数字。

例如:

A就是一个位段类型。位段类型里面的成员必须同一个类型,大部分情况下是int类型和char类型

冒号后面的数字表示这个成员占多少个比特位,例如_a原本占一个整型4字节,现在只占2个比特位。

4.2 位段的内存分配

(1) 位段的成员可以是 int unsigned int signed int 或者是 char 等类型
(2) 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的⽅式来开辟的。也就是
根据类型(例如int)一次性开辟4个字节,当这4个字节不够用时再一次性开辟4个字节。
(3)  位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段。
案例:
位段类型是char类型,一次性开辟1个字节=8个bit。a占3个bit后剩5个bit;b再用去4个bit剩1个不
够c用就再开辟1个字节=8个bit,接着放c后剩3个bit,不够d用就再开辟一个字节放d。所以整个位
段结构体占内存空间3个字节
接着将要存入abcd的数值转化为二进制,根据每个类型分配的bit进行存储,可能会出现截断现
象。(例如:10的二进制:1010;而a只能放3个bit,所以截断后010放入a中)
一般内存中存储的是十六进制,若要调试看推理的过程对不对,要将存放的二进制转为十六进制

4.3 位段跨平台和注意事项

(1)int 位段被当成有符号数还是无符号数是不确定的

(2)位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会出问题。

(3)位段中的成员在内存中从左向右分配,还是从右向左分配,标准尚未定义。

(4)当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利⽤,这是不确定的。

总结:

跟结构相⽐,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在,要自己根据不同平台定义不同位段。

使用注意事项:

位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些
位置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。所以不
能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊放在
⼀个变量中,然后赋值给位段的成员。


http://www.mrgr.cn/news/52050.html

相关文章:

  • c#编写的各类应用程序
  • 65.DDR3读写控制器的设计与验证(2)
  • 60. 排列序列
  • Windows11桌面快捷方式图标变为白色方块-如何解决
  • C++11 使用 {} 进行初始化
  • 【微信小程序_18_WXS脚本】
  • TemporalBench:一个专注于细粒度时间理解的多模态视频理解的新基准。
  • 从实习到春招成为一名安全工程师,我经历了什么
  • mqtt与云服务器
  • 2024了,传统行业转行AI,可不可行?
  • Java 虚拟机(JVM)中的内存泄漏排查技巧及各种内存查看命令分析工具推荐
  • C语言中点操作符(.)和箭头操作符(->)的区别
  • 汽车免拆诊断案例 | 2023款零跑C01纯电车后备厢盖无法电动打开和关闭
  • 对“一个中心,三重防护”中安全管理中心的理解
  • 数据结构深度优先搜索遍历连通图+非连通图(C语言代码+遍历+终端输入内容)
  • 超详细的B/S和C/S架构对比
  • 【PT-RS】
  • SIEMENS罗宾康LDZ14501001.140功率单元适合哪些场合使用?
  • 【论文阅读】03-Diffusion Models and Representation Learning: A Survey
  • 使用Python语言结合OpenCV库来处理视频流和条形码/二维码的识别