大家好,我是晓星航。今天为大家带来的是结构体、位段、枚举和联合的知识点讲解!😀
1. 结构体声明
1.1 结构的基本知识
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
1.2结构的声明
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181101857.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181102054.png)
1.3 特殊的声明
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181103389.png)
1.4 结构的自引用
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181104007.png)
用指针来引用
1.5 结构体变量的定义和初始化
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181104602.png)
补充:有无typedef区别:
有typedef的话,在定义时即可无需再加stuct 可直接写成:
stu s ={“zhangsan”, 20, 95.5f};
无typedef的话,在定义时就要写成
struct stu s ={“zhangsan”, 20, 95.5f};
总结:即无typedef的话在定义变量时就要加上struct这个关键字
1.6 结构体内存对齐
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181530494.png)
例题1:
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181531417.png)
问题:我们的想法是struct S1占6个字节 但是为什么他占了12个字节呢?(这里与结构体的内存齐数有关)
我们接着往下看!
offsetof(函数) - 可以算一个结构体的成员相较于这个结构体的起始位置的偏移量
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181533398.png)
vs环境默认对齐数:8
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181533666.png)
例题2:
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181533409.png)
例题3:
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181534791.png)
例题4:
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181534000.png)
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
那么说了这么多,我们为什么要引入结构体的内存对齐呢?
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181537288.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181537950.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181537296.png)
内存对齐的最大优点:结构体的内存对齐是拿空间来换取时间的做法。
让占用空间小的成员尽量集中在一起。
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181537262.png)
S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。(因为我们在S2中把char类型的变量都调到了上面)
1.7 修改默认对齐数
虽然每个平台给的默认对齐数不一样,但我们可以根据我们不同的需求将对齐数进行修改,一般修改为2^n。
修改方法如下:
#pragma pack(n); //设置默认对齐数为n
#pragma pack(); //取消设置的默认对齐数,还原为默认
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181542474.png)
eg:当默认对齐数为vs的8时:
当默认对齐数修改为4时:
通过上面例题中修改对齐数前后我们可以发现,我们通过降低对齐数可以节省内存,提高效率。
1.8 结构体传参
结构体传参优先传地址 因为可以节省空间
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181545769.png)
2. 位段
2.1 什么是位段
位段的作用是节省空间。用更少的空间做更多的事情
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181545673.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181545121.png)
冒号后面就代表他们分别占几个比特位
eg:a占2个bit b占5个bit c占10个bit d占30个bit
下面我们附上内存大小转换图供大家参考:
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181622208.png)
2.2 位段的内存分配
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181547663.png)
例如一个整形需要开辟4个字节,也就是32个bit,而一个字符需要开辟1个字节,就是8个bit。但如图所示,在使用了位段后,一个字节可以就使用3或4个bit,剩下的5或4个字节就可以给下一个字符继续使用!😶
注://后面是剩下的bit数量
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181623663.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181548289.png)
位段每次使用会开辟一个字节即8个bit 如果这个字节不够接下来所需的bit则会开辟1个新的字节
没有用到的比特位即被丢掉了(浪费了)
2.3 位段的跨平台问题
1.int 位段被当成有符号数还是无符号数是不确定的。
2.位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
总结:跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。
2.4 位段的应用
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181549648.png)
3. 枚举
枚举顾名思义就是一一列举。
把可能的取值一一列举。
比如我们现实生活中:
一周的星期一到星期日是有限的7天,可以一一列举。
性别有:男、女、保密,也可以一一列举。
月份有12个月,也可以一一列举
这里就可以使用枚举了。
3.1 枚举类型的定义
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181549736.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181549765.png)
这里的枚举变量的值是默认从第一个元素为0开始,后面的元素依次加1。
如果我们自己给定了值而后面元素没给值则后面元素会默认从给定的值依次加1。eg:上图中MALE等于4,则后面的FEMALE和SECRET依次为5和6。
也可以用typedef重命名
3.2 枚举的优点
枚举的优点:
1.增加代码的可读性和可维护性
2.和#define定义的标识符比较枚举有类型检查,更加严谨。
3.防止了命名污染(封装)
4.便于调试
5.使用方便,一次可以定义多个常量
3.3 枚举的使用
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181550749.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181550849.png)
这里因为没有赋初始值enum自动给EXIT赋值为0,然后其余值为1 2 3 4 5 6自动增长,很好的实现了我们菜单的选项功能同时也提高了我们代码的可读性(即一眼就可以看出我们这个功能是什么,完美的避开了数字命名功能还需要我们去思考这个数字代表什么功能).😀
4. 联合(共用体)
4.1 联合类型的定义
联合也是一种特殊的自定义类型这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
4.2 联合的特点
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
适用于:你不会同时使用里面的变量,即一次只会使用union中的一个变量。
优点:大大节约了数据所占的空间。
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181551337.png)
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181551186.png)
例题:判断当前计算机的大小端存储
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181552280.png)
我们先看看什么是大端什么是小端。
大端存储模式:数据的低位保存在内存中的高地址中,数据的高位保存在内存中的低地址中;
小端存储模式:数据的低位保存在内存中的低地址中,数据的高位保存在内存中的高地址中;
基础版写法1:
升级版本写法2:
升级版本写法3:
4.3 联合大小的计算
![](https://7078909xxh.oss-cn-shanghai.aliyuncs.com/csdn图床专用区/202209181555673.png)
Un1中c占5个字节,但是它的对齐数为1,因此再union中int对齐数为4,总共占8个字节
Un2中short c[7]占14个字节但是他不是最大对齐数4的整数倍,因此我们还要加2个字节,即使16个字节
感谢各位读者的阅读,本文章有任何错误都可以在评论区发表你们的意见,我会对文章进行改正的。如果本文章对你有帮助请动一动你们敏捷的小手点一点赞,你的每一次鼓励都是作者创作的动力哦!😘