【C语言】——联合体与枚举

【C语言】——联合体与枚举

    • 一、联合体
      • 1.1、联合体类型的声明
      • 1.2、联合体的特点
      • 1.3、相同成员的结构体和联合体对比
      • 1.4、联合体的大小计算
      • 1.5、联合体的应用举例
      • 二、枚举
        • 2.1、枚举类型的声明
        • 2.2、枚举类型的优点

          一、联合体

          1.1、联合体类型的声明

            

            联合体也叫做共用体

            与结构体一样,联合体也是自定义类型,同样,也是由一个或多个的成员构成,这些成员类型可以相同也可以不同。

            与结构体不同的是,编译器只会为联合体中最大的成员开辟足够的内存空间。正如联合体这个名字一样,联合体的所有成员共用这一块内存空间。

            这样,因为使用的是同一块内存,一个联合体成员改变,其他联合体成员也会跟着改变。

            

            联合体的声明与结构体非常类似,下面我们直接看代码:

          #include//联合类型的声明
          union Un
          {char c;
          	int i;
          };
          int main()
          {//联合变量的定义
          	union Un un = { 0 };
          	//计算各个变量的大小
          	printf("%d\n", sizeof(un));
          	return 0;
          }
          

            

          运行结果:

            为什么大小是 4 呢?我们一起来学习联合体的特点

            

          1.2、联合体的特点

            联合体最大的特点就是所有成员共用一块内存空间,因此联合体变量的大小,至少是最大成员变量的大小(因为联合体至少保证有能力存储那个成员)

            

            我们可以通过代码来理解联合体的特点

            

          代码一:

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

            

          运行结果:

            

          代码二:

          #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;
          }
          

          运行结果:

            

            可以看到,代码一中,取出的三个地址都是一样的,说明成员之间共用一个内存空间

            

            至于代码二,我们发现低位字节的内容改了,我们可以通过画图来分析

            

            

            看到这里,不知大家有没有联想到判断大小端存储(详情请看【C语言】——数据在内存中的存储),是的,我们可以利用联合体来对判断机器是大端存储还是小端存储

            

          int check_sys()
          {union
          	{int i;
          		char c;
          	}un;
          	un.i = 1;
          	return un.c;
          }
          

            

            我们往联合体成员 i i i 中放入1,在返回联合体成员 c c c,因为 c c c 是 c h a r char char 类型,取出的是 i i i 中地址最小的字节的内容,当取出值为 1,说明低位数字放低地址,为小端存储;如果为 0,说明低位数字放高地址,为大端存储

            

            

          1.3、相同成员的结构体和联合体对比

            

            下面,我们来对比一下相同成员的结构体和联合体的内存布局情况:

          struct S
          {char c;
          	int i;
          };
          union Un
          {char c;
          	int i;
          };
          

            

            

          1.4、联合体的大小计算

            

            首先,我们来看下面两种联合体的大小

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

            

          运行结果:

            

          为什么会这样呢?联合体的大小是怎么计算的呢?它满足两条规则:

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

              

            图示:

              通过这图,就能很好地分析出上面两个联合体的大小啦

              

              

            1.5、联合体的应用举例

              

              结构体的使用,最主要的是节省空间

              现在有这么一个场景:我们要举办一个活动,要上线一个礼品兑换单,兑换单中有三种商品:图书、杯子、衬衫。每一种商品都有:库存量,价格、商品类型以及和商品类型相关的其他信息

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

                我们不耐心思考,直接写出一下结构

              struct gift_list
              {//公共属性
              	int stock_number;//库存量
              	double price;//定价
              	int item_type;//商品类型
              	//特殊属性
              	char title[20];//书名
              	char autor[20];//作者
              	int num_pages;//页数
              	char design[30];//设计
              	int colors;//颜色
              	int sizes;//尺寸
              };
              

                

                上述的结构设计的其实很简单,用起来也很方便,但是结构汇的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单种的商品来说,只有部分属性信息是常用的,比如:

                

                商品时图书,就不需要 d e s i g n design design、 c o l o r s colors colors、 s i z e s sizes sizes

                

                所以我们就可以把公共属性单独写出来,剩余属于各种商品本身的属性使用联合体这样就可以减少内存所需要的内存空间,一定程度上节省了内存。

                

              struct gift_list
              {//公共属性
              	int stock_number;//库存量
              	double price;//定价
              	int item_type;//商品类型
              	//特殊属性
              	union {struct
              		{char title[20];//书名
              			char autor[20];//作者
              			int num_pages;//页数
              		}book;
              		struct
              		{char design[30];//设计
              		}mug;
              		struct
              		{char design[30];//设计
              			int colors;//颜色
              			int sizes;//尺寸
              		}shirt;
              	};
              };
              

                

                

              二、枚举

              2.1、枚举类型的声明

                C语言中枚举是什么?没错,就是你想的那个枚举

                枚举就是一一列举

                把可能的取值一 一列举

                当然,一 一列举的前提是他是有限个数

                

              比如:

              • 一周的天数是有限的,7天,可以一一列举
              • 性别有:男、女、保密,可以一一列举
              • 三原色,可以一一列举

                  

                这些数据的表示就可以使用枚举了

                enum Day//星期
                {Mon,
                	Tues,
                	Wed,
                	Thur,
                	Fri,
                	Sat,
                	Sun
                };
                enum Sex//性别
                {MALE,
                	FEMALE,
                	SECRET
                };
                enum Coloe//颜色
                {RED,
                	GREEN,
                	BLUE
                };
                

                  

                  上述定义的 e n u m enum enum D a y Day Day 、 e n u m enum enum S e x Sex Sex、 e n u m enum enum C o l o r Color Color 就是枚举类型

                  而{}中的内容就是可能的取值,也叫枚举常量

                  这些可能取值都是有值的,默认从 0 开始,依次往后递增 1

                  

                当然,我们定义枚举类型时,也可以自己给它赋初值

                enum Coloe//颜色
                {RED = 2,
                	GREEN = 4,
                	BLUE = 8
                };
                

                  

                  

                2.2、枚举类型的优点

                  我们可以用 # d e f i n e define define 为什么还要用枚举呢?

                  

                相比与 # d e f i n e define define,枚举有以下优点

                • 增加代码的可读性可维护性
                • 和 # d e f i n e define define 定义的标识符相比,枚举类型有类型检查,更加严谨
                • 便于调试,预处理阶段会替换 # d e f i n e define define 定义的符号
                • 方便使用,一次可定义多个常量
                • 枚举常量是遵从作用域规则的,枚举声明在函数范围内,只能在该函数内部使用。

                    

                  枚举类型的使用

                  enum Color//颜色
                  {RED=1,
                  	GREEN=2,
                  	BLUE=4
                  };
                  enum Color clr = GREEN;//使用枚举常量给枚举变量赋值
                  

                    那我们不禁想:是否可以拿整数给枚举常量赋值呢?在 C语言 中是可以的,但是在 C++ 是不行的,C++ 的类型检查比较严格。

                    

                    

                    

                    


                    好啦,本期关于联合体与枚举的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在C语言的学习路上一起进步!