本篇会加入个人的所谓‘鱼式疯言’
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

前言

在本篇文章中,小编将带领友友们体验联合体和枚举的奥妙之处
下面有请我们今天的主角闪亮登场

目录

1.联合体
2.枚举

一. 联合体

. 联合体类型的概念

union union_name { member_type1 member1; member_type2 member2; ...};

union_name 是联合体的名称
member_type1、member_type2 是成员的数据类型
member1、member2 是成员的名称

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以不同的类型。
但是编译器只为最大的成员分配足够的内存空间。
联合体的特点是所有成员共用同一块内存空间
所以联合体也叫:共用体

. 联合体的特点

第一个特点:

先请宝子们看一段代码
思考一下哦! ! !

#include //联合类型的声明union Un{char c;int i;};int main(){//联合变量的定义union Un un = { 0 };// 下面输出的结果是一样的吗?printf("%p\n", &(un.i));printf("%p\n", &(un.c));printf("%p\n", &un);return 0;}

可以很明显的看出他们的地址居然是一模一样哒。

是哒,这就是为什么小编会说,联合体中的成员共同同一块空间了 。
见图也可知晓哦。❤️ ❤️ ❤️

第二个特点:

老规矩,还是先看代码哦! ! !

#include //联合类型的声明union Un{char c;int i;};int main(){//联合变量的定义union Un un = { 0 };un.i = 0x11223344;un.c = 0x55;printf("%x\n", un.i);return 0;}


我们发现将i的第4个字节的内容修改为55了

就充分体现了给联合体其中一个成员赋值,其他成员的值也跟着变化的特点。

鱼式疯言

联合体的主要特点用大白话来说就是:

同空间,互影响,可改变。

.联合体大小

重要的提前说

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

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

证明过程如下

#include union Un1{int i;char c;};union Un2{short c[7];int i;};int main(){//下面输出的结果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;}

联合体的大小又谁决定,肯定是由最大的那块数据类型决定,

但我们前提是的至少哦

如果超过了怎么办,我们就必须想结构体一样,利用内存对齐来分配我们的空间大小。

什么! ! !
小爱同学说没有看过我写的结构体内存对齐
那小编就把对应标题链接粘贴在这帮助各位友友一起理解哦
《来 ! 来 ! 来 ! 瞧瞧伏地魔大哥是怎么看C语言结构体的 ! ! !》 http://t.csdnimg.cn/XL9n2

鱼式疯言

最大成员是对齐数的整数倍时,整体就是最大内存

不是的话,就要和结构体对齐一样办,整体内存就是对齐后的内存

是不是有小伙伴就疑惑了,我们结构体和联合体的区别在哪呢

好学的友友们请看下个小标题哦,精彩马上呈现

. 联合体与结构体的对比

#include//定义结构体类型struct S{char c;int i;};//定义联合体类型union Un{char c;int i;};int main(){//计算各种大小printf("%zd\n", sizeof(struct S));printf("%zd\n", sizeof(union Un));return 0;}



有图有真相

鱼式疯言

简而言之,言而简之。

我们的结构体成员不会互相影响,但占内存

我们的联合体会互相影响,但不占内存

. 联合体的实际运用

栗子 一:

使用联合体是可以节省空间的,举例:
比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。
每一种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。
图书:书名、作者、页数
杯子:设计
衬衫:设计、可选颜色、可选尺寸
那我们不耐心思考,直接写出一下结构:

//第一种结构体分布//定义一个结构体礼物struct gift_list1{//相同的属性//库存量int nums;//价格float prize;//商品类型char type[20];//书名char bookname[30];//作者char autor[20];//页数int num_book;//设计char dec[50];//颜色char color[20];//大小int sizes;};

如果我们插入联合体的把不同的结构体属性联合起来就可以节省我们的内存

神奇的代码一:

//第二种插入联合体的结构体分布//定义一个结构体礼物struct gift_list2{//相同的属性//库存量int nums;//价格float prize;//商品类型char type[20];//将不同属性的也联合起来union pu{struct book{//书名char bookname[30];//作者char autor[20];//页数int num_book;};struct cup{//设计char dec[50];};struct shirt{//设计char dec[50];//颜色char color[20];//大小int sizes;};};};

栗子二:

如何判断大小端存储 ? ? ?
假如小爱同学没学联合体之前,肯定会这样写代码
小编说的是假如哦

//判断大小端存储_test//指针强转法int conc1(void){int a = 1;return *(char*)(&a);}int main(){int c1 = conc1();if (c1==1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;}


但你今天学了小编写的联合体的介绍,友友们不妨这样写代码吧

//联合体union MyUnion{int i;struct MyStruct{char s1;char s2;char s3;char s4;};};//结构体法int conc2(void){//00 00 00 01 大端存储//01 00 00 00 小端存储union MyUnion a = { 0 };a.i = 1;return a.s1;}int main(){int c2 = conc2();if (c2==1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;}


因为 s1 的全部数据 与 i 的前一个字节数据是一致的
所以我们只需要抽离出对应的 s1 即可

鱼式疯言

从中我们看到的联合体本质是联合不同的内存,从中达到节省空间的良效

同时利用公用同一块内存空间的便利,可以有效抽离每个字节的数据

二. 枚举

.枚举的简介

C语言中,枚举是一种用来定义一组具名整数常量的数据类型。枚举类型定义了一系列的枚举常量,也称为 枚举成员。每个枚举常量都有一个对应的整数值,可以在程序中使用这个整数值来表示相应的枚举常量

enum Weekday { MONDAY,// 0 TUESDAY, // 1 WEDNESDAY, // 2 THURSDAY,// 3 FRIDAY,// 4 SATURDAY,// 5 SUNDAY // 6};

枚举类型的定义使用关键字 “enum”,后面跟着枚举类型的名称,然后是一对花括号 {} ,其中列出枚举常量。每个枚举常量都可以显式地指定一个整数值,如果没有指定,默认从 0 开始递增

鱼式疯言

从我们的枚举的简介中就可以提炼出很多至关重要的信息

一. 枚举本身是 常量

二. 枚举和结构体,联合体一样都是属于自定义的一种 数据类型

三. 枚举只能常量只能表示的 整数

四. 枚举是默认从 0 开始递增的,也可初始化第一个为 非0 但依然保持递增的原则,除非每个枚举成员都被赋值 (友友们看下面两栗子自然就明白了)

. 举俩个栗子

栗子 一

//枚举类型的定义enum MyEnum{one=1,two,three};int main(){int n = 0;scanf("%d", &n);switch (n){case one:printf("one\n");break;case two:printf("two\n");break;case three:printf("three\n");break;}return 0;}


我们可以用这些枚举常量来替换我们case的整数值,以此来增加代码的可读性

鱼式疯言

枚举常量与普通常量之间可以替换

爱提问的小爱同学就要问了,为啥好像用 #define 宏定义枚举常量也是可以的哦 ! ! !
但我们为啥要用枚举呢,这个问题小爱同学问的很好啊。那我们来试试宏定义的效果如何吧

//宏定义的常量#define one 1#define two 2#define three 3int main(){int n = 0;scanf("%d", &n);switch (n){case one:printf("one\n");break;case two:printf("two\n");break;case three:printf("three\n");break;}return 0;}


哇塞,没想到效果一样嘞
小爱同学又有疑问了 ” />栗子二(c++的环境测试)

//枚举定义enum MyEnum{one,two,three};int main(){int n = 0;scanf("%d", &n);enum MyEnum e = 2;switch (n){case one:printf("one\n");break;case two:printf("two\n");break;case three:printf("three\n");break;}return 0;}


友友们是不是想为啥会报错呢? ? ?
这时聪明的小爱同学就大胆的说出了他的想法:
因为这是枚举类型不能匹配整型类型,就会报错
小编不得不为小爱同学点赞哦,完全正确

没错小编提过枚举类型是也是 数据类型 哦,如果出现类型不匹配就很有可能出现 警告和报错

鱼式疯言

无论是什么枚举类型,联合体类型,结构体类型,温馨提示下友友们都记得类型同一哦 ❤️ ❤️ ❤️

. 枚举类型的与宏定义的差别

在上面的中我们可以明显的看到,枚举有类型检查吧,我们宏定义是没有的呢。
所以小编总结了一下五点

  1. 增加代码的可读性和可维护性
  1. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  1. 便于调试,预处理阶段会删除#define 定义的符号
  1. 使用方便,一次可以定义多个常量
  1. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用

鱼式疯言

总之枚举的使用可谓是优势俱全啊
但小编的想法是

建议友友们相同类型的常量我们更常用枚举

如果是不同类型的常量我们更常用宏定义来解决呢

总结

在本篇文章中,小编主要带着大家理解了

  • 联合体:熟悉了联合体的定义并知晓了实际的使用场景,还有联合体相比于结构体的优势
  • 枚举:熟悉了枚举如何定义,枚举需要注意的哪些点,以及枚举相比于宏定义的优势

如果觉得小编写的还不错的咱可支持三关下,不妥当的咱评论区指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大动力