当前位置:首页 » 《随便一记》 » 正文

关于我、重生到500年前凭借C语言改变世界科技vlog.20——自定义类型:联合&&枚举

23 人参与  2024年11月19日 14:01  分类 : 《随便一记》  评论

点击全文阅读


文章目录

1.联合体1.1 联合体的声明及定义1.2 联合体的内存计算1.3 联合体和结构体比较1.4 大小端介绍1.5 联合体的应用 2.枚举2.1 枚举的声明2.2 枚举的应用 希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力!

在上一篇博文中我们学习了常见自定义类型中的一种——结构体,如果我们想要用常量准确表示一系列颜色,表示星期一到星期日这些变量呢?那么枚举就是一种合适的类型;如果我们即想在一块区域内存储不同的变量,又想节省内存空间呢?那么联合体就是一种有效的类型,接下来将对这两种自定义类型进行详细的介绍?

1.联合体

什么是联合体?联合体也称共用体,顾名思义,共用共用就有节省空间的意思,它允许在相同的内存位置存储不同的数据类型,就是个缩小内存的结构体

1.1 联合体的声明及定义

联合体的声明,定义与结构体相同,只是类型不同,其语法形式为

union tag{    member-list;}variable-list;

声明就是去掉 variable-list ,保留剩下的,可以在结构体上定义,也可以另起一行定义对象
上一篇结构体声明与定义有详细介绍

传送门:关于我、重生到500年前凭借C语言改变世界科技vlog.19——自定义类型:结构体

联合体的初始化也有特殊之处

#include <stdio.h>//联合类型的声明union Un{ char c; int i;};int main(){ //联合变量的定义 union Un un1 = {0}; union Un un2 = {'a'}; printf("%d\n", un1.i);  printf("%d\n", un2.i);  return 0;}

按照联合体初始化规则,初始化赋值时将值赋给第一个成员

赋值为 0 的情况:这是一种特殊情况,通常情况下只会将初始化的值赋给第一个变量,但是初始化为 0 在编译器的角度下是一种自然状态,编译器会将这个全 0 的状态自然地扩展到整个联合体的内存空间。这就好比在一个容器中倒入了无色无味的清水,清水会自然地填满整个容器。所以整个 un1 结构体都初始化为 0,即 un1.i = 0赋值为其他值的情况:当用 ‘a’ 初始化联合体的第一个成员(如 char 类型)时,只会将 ‘a’ 的 ASCII 码值 97 存储在第一个成员对应的内存位置(即将 01100001 存在字符 c 中)
那如果用个很大的数,比如 9999 ,对于 9999 的二进制表示 00000000 00000000 00100111 00011111,实际存储到 c 中的就是 00011111,所以其余 3 个字节是未初始化的垃圾数据,如果访问整型 i 得到的结果是不可预测的,即 un2.i = 随机值

1.2 联合体的内存计算

联合体与结构体最大的不同就是不会浪费内存,尽可能节省空间,这样⼀个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)

请添加图片描述
代码1 输出:001BC63F、001BC63F、001BC63F
代码2 输出:11223355

不难发现联合体的部分或整体地址都一样,整型 i 的数据被字符 c 覆盖,这是为什么呢?

地址从高到低存放 44332211 ,而联合体是共用空间的,所以把 55 覆盖在 44上。有人就会有疑惑了,为什么不是地址从低到高存放 44332211,把 55 覆盖在 11上,这就和数据的字节存储方式有关了,马上就会介绍到。
言归正传,把字符 c 覆盖在 整型 i 上,i 就无法使用了,所以联合体就是一种能够使用多种类型的集合体,但每次想要使用就要对要使用的值赋值,覆盖之前的数据,使想要的数据有完整的值,处于能正常访问的状态

那么联合体的大小究竟如何计算呢?

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

1.3 联合体和结构体比较

对比结构体和联合体的空间存储情况就能清楚地知道为什么联合体能节省空间了

union S//struct S{ char c; int i;};union S s = {0};//struct S s = {0};

分别在空间中的存储情况
在这里插入图片描述
黄色部分是浪费的空间,明显结构体为了能完整存储每个变量,会采取空间换时间的方式

1.4 大小端介绍

什么是大小端?

大端也叫大端序或大字节序,数据的高位字节存于低地址,低位字节存于高地址叫小端序或小字节序,与大端相反,数据的低位字节存于低地址,高位字节存于高地址

这就可以解答我们上面的疑惑了,“地址从低到高存放 44332211,把 55 覆盖在 11上” 是因为机器采用了小端存储的方式,不同的机器的存储方式各有不同,根据其所处的环境和需求决定

如何通过代码判断大小端?

int check_sys(){ union { int i; char c; }un; un.i = 1; return un.c;//返回1是⼩端,返回0是⼤端}

1.5 联合体的应用

比如,我们要搞⼀个活动,要上线一个礼品兑换单
礼品兑换单中有三种商品:图书、杯子、衬衫
每一种商品都有:库存量、价格、商品类型和商品类型相关的其他信息

图书:书名、作者、页数杯子:设计衬衫:设计、可选颜色、可选尺寸

如果使用结构体就要把所有物品,不论是公共属性,还是特殊属性都要表示出来
如果使用结构体就可以把特殊属性作为结构体放在联合体里,要用哪个就赋值哪个,能省下不少空间

struct gift_list{ int stock_number;//库存量 double price; //定价 int item_type;//商品类型  union  { struct { char title[20];//书名 char author[20];//作者 int num_pages;//⻚数 }book; struct { char design[30];//设计 }mug; struct { char design[30];//设计 int colors;//颜⾊ int sizes;//尺⼨ }shirt; }item;};

2.枚举

**什么是枚举?**枚举用于定义一组命名的常量,例如,在一个表示星期的程序中,我们可以定义一个枚举类型来代表一周的七天,而不是使用数字 0 - 6 来分别表示星期一到星期日

2.1 枚举的声明

表示星期:

enum Day//星期{ Mon, Tues, Wed, Thur, Fri, Sat, Sun};

表示颜色

enum Color//颜⾊{ RED, GREEN, BLUE};

{}中的内容是枚举类型的可能取值,也叫 枚举常量,这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值

比如颜色枚举常量,从上到下默认为RED、GREEN、BLUE赋值0、1、2

为什么非要用枚举常量,用宏定义(#define)不也可以吗?

• 增加代码的可读性和可维护性

• 和 #define 定义的标识符比较枚举有类型检查,更加严谨

• 便于调试,预处理阶段会删除 #define 定义的符号

• 使用方便,一次可以定义多个常量

• 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用

这里只要知道枚举常量在各种意义上来说,表示一系列常量时是优于宏定义,关于预处理阶段的宏定义,会在后续进行详细介绍

2.2 枚举的应用

enum Color//颜⾊ { RED=1, GREEN=2, BLUE=4 }; enum Color clr = GREEN;

枚举量可以作为常量给变量赋值,这里提醒一下,在 switch 语句中,case 后面也可以接枚举量,这能使代码的可读性更高

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述


点击全文阅读


本文链接:http://zhangshiyu.com/post/188736.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1