C语言进阶 —— 枚举与联合

前言

今天我们会给大家介绍一下枚举和联合体这两个概念,这两者我们其实和结构体结合起来对比学习,三者之间都有其相似之处,当然也有不小的区别,我们今天将会从枚举和联合体的基本定义入手,剖析二者的使用和功能。

一、枚举

我们先讲枚举,从字面意义上来说,枚举的意思就是一一列举

即把所有有可能的值一一列举

比如说:一月份一共有31天,这是有限的,我们是可以一一列举的

又如:性别只有三种情况,男、女或者保密,我们也可以一一列举

等等…

诸如此类,我们都可以称其为列举

在这种情况下我们就可以使用枚举了

1.1 枚举类型的定义

先来看几个例子:

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

enum Sex  //性别
{
    MALE,
    FEMALE,
    SECRET
};

以上定义的 enum Day,enum Sex都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫枚举常量 。

那如果现在我们想描述一下星期应该怎么用代码表达出来呢?我们可以这样做:

int main()
{
	enum Day d = Fri;
	
	return 0;
}

以此类推,其他的枚举类型也是如此

在这里可能有人会问了,既然大括号内的内容叫做枚举常量,那么枚举常量有没有值呢?

在这里我可以很明确的告诉大家,这些枚举常量都是有值的,大家可以尝试用printf函数将所有的枚举常量的值一一打印出来比对一下,

我们很容易就可以发现一个有趣的规律:我们枚举的可能取值都是从0开始的,依次往下递增1,当然这里的前提是默认情况下。

那么我们是否可以修改它们的值呢?比如我希望第一个枚举常量从1开始,其实这是很容易实现的,只需将"Mon"改为"Mon = 1"即可。

后面的枚举常量也和默认情况下一样依次递增1。

1.2 枚举的优点

为什么使用枚举?使用枚举的好处是什么?

首先我们知道,除了使用枚举,我们还可以使用#define定义常量,如:

#define Mon 1
#define Tues 2
//....

既然我们也可以使用define来定义一个常量,那相较于它而言,枚举的优势在哪里呢?

我们来看看枚举的优点:

  1. 增加代码的可读性和可维护性。

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

  3. 防止了命名污染

  4. 便于调试

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

1.3 枚举的使用

看一个简单的例子大家就明白了:

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

enum Color clr = GREEN;   //只能拿枚举常量个枚举变量赋值,才不会出现类型的差异
clr = 5;

二、联合体(共用体)

2.1联合类型的定义

联合也是一种特殊的自定义类型

这种类型定义的变量也包含一系列成员,特征是这些成员公用同一块空间(所以联合体也叫共用体)

比如:

union Un
{
  int a;
  char c;
};

那我们要怎么理解这个共用呢?我们可以进行下面这个操作:

int main
{
	union Un u;
    printf("%d\n", sizeof(u));
    return 0;
}

按照我们惯有的思维习惯,一个整型+一个字符型至少也得占用5个字节

可是当我们执行程序后发现,只占用了4个字节,这就充分体现出了共用这一个特点。

我们可以再来看看二者的地址:

printf("%p\n", &u);
printf("%p\n", &(u.a));
printf("%p\n", &(u.b));

执行后我们可以发现,这三个地址是一模一样的,我们该如何解释呢?

其实解释起来非常简单:
在这里插入图片描述

我们先画出四个字节的空间,黄色部分就是a所占用的空间,而褐色部分就是b所占用的空间,他覆盖了a的一部分空间,但是二者是共存的,并不会有互斥的现象,这和共用体的名字也非常合拍。

2.2 联合的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合体至少得有能力保存最大的那位成员)。

我们在上文提到了共用这一概念。那有人就会提出问题,两者的地址是一样的,当你对其中一个变量进行改变时 ,另一个变量在内存中也会被改变,这就会产生问题了啊。

正是因为有这样的问题,所以我们要在实际使用时,我们在同一时间, 只使用其中一个变量,用了其中一个变量就不用另外的变量,这样就可以避免这个问题。

2.3 联合大小的计算

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

来看一个例子:

union Un1
{
	char c[5];
	int i;
};

union Un2
{
	short c[7];
	int i;
};

//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));

执行程序后我们发现,结果分别是8和16。这是为什么呢?

对于un1,当有数组的时候,最大对齐数为数组成员,un1中为char ,对齐数就是1,int 为4是un1中最大对齐数,故结果为8。

un2同理,short为2,数组共14,但是最大对齐数为4,整数倍故为16。

总结

在这里插入图片描述