目录
- [1. 联合体类型](#1. 联合体类型)
-
- [1.1 联合体类型的声明](#1.1 联合体类型的声明)
- [1.2 联合体的特点](#1.2 联合体的特点)
- [1.3 相同成员的结构体和联合体的对比](#1.3 相同成员的结构体和联合体的对比)
- [1.4 联合体大小的计算](#1.4 联合体大小的计算)
- [1.5 联合的一个练习](#1.5 联合的一个练习)
- [2. 枚举类型](#2. 枚举类型)
-
- [2.1 枚举类型的声明](#2.1 枚举类型的声明)
- [2.2 枚举类型的优点](#2.2 枚举类型的优点)
- [2.3 枚举类型的使用](#2.3 枚举类型的使用)

1. 联合体类型
1.1 联合体类型的声明
像结构体一样,联合体也是由多个成员构成的,这些成员可以是不同类型,也可以是同一类型。联合体的关键字是 union。在联合体中,所有成员共用同一块内存空间,编译器会为能够容纳最大成员的对象分配空间,但由于内存对齐要求,联合体的实际大小可能大于最大成员的大小 。因此,联合体通常用于在同一块内存中存放不同类型的数据。给联合体中的某个成员赋值时,会改变这块共享内存的内容,其他成员读取到的结果也会受到影响。
c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//联合体的声明
union Un
{
int a;
float b;
char c;
};
int main()
{
//联合体的定义
union Un un = { 0 };
printf("%zu\n", sizeof(union Un)); //4
return 0;
}
1.2 联合体的特点
联合体的所有成员共用同一块内存空间,因此联合体变量所占的内存大小至少 能够容纳其中最大的成员 。但由于内存对齐 的影响,联合体的实际大小可能大于最大成员的大小。
c
union Un
{
char c;
int i;
};
int main()
{
union Un un;
printf("&un = %p\n", &un);
printf("&(un.c) = %p\n", &(un.c));
printf("&(un.i) = %p\n", &(un.i));
return 0;
}

画图演示一下:

如果将一个变量赋值或者修改其中一个变量,会改变共享这块内存的内容,其他变量的内容读取到的结果也可能收到影响:
c
union Un
{
char c;
int i;
};
int main()
{
union Un un;
un.i = 0x11223344;
un.c = 0x55;
return 0;
}

画图来演示一下:

1.3 相同成员的结构体和联合体的对比
我们来比较相同成员的结构体和联合体的布局情况。
c
//代码1
struct S
{
char c;
int i;
};
struct S s = { 0 };
//代码2
union Un
{
char c;
int i;
};
union Un un = { 0 };
画图进行对比:

1.4 联合体大小的计算
由于联合体大小的计算需要涉及到内存对齐 的相关知识点,所以读者可以在自定义类型:结构体中进行学习。
联合体大小计算规则 : 联合体大小计算规则: 联合体大小计算规则:
-
联合体的大小至少等于 最大成员的大小。
-
为满足内存对齐 要求,联合体的总大小 通常需要是最大对齐数 的整数倍 ;如果不是,则会自动填充到对应的整数倍。
c
#include <stdio.h>
//代码1
union Un1
{
char c[5];
int i;
};
//代码2
union Un2
{
short c[7];
int i;
};
int main()
{
//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}
画图演示:

使用联合体是可以节省 空间的,举一个例子:
比如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。
图书:书名、作者、⻚数
杯⼦:设计
衬衫:设计、可选颜⾊、可选尺⼨
一般我们是这样写的:
c
struct gift_list
{
//公共属性 - 抽象成一个结构体
int stock_number;//库存量
double price; //定价
int item_type;//商品类型
//特殊属性
char title[20];//书名
char author[20];//作者
int num_pages;//⻚数
char design[30];//设计
int colors;//颜⾊
int sizes;//尺⼨
};
上述结构体虽然写法直观、使用方便,但它把所有商品可能涉及的属性都放在同一个结构中。
这样设计虽然统一了数据形式,却也带来了明显的问题:不同商品拥有各自独立的特征,而这些特征并不会同时使用 。因此,把所有属性都统一存储在同一个结构体中,会导致结构体体积增大,造成不必要的内存浪费。
例如,商品若是图书,就只需要书名、作者、页数 等信息,并不需要设计、颜色、尺寸 这些属性;而商品若是杯子或衬衫,又只会使用属于自身类别的那部分数据。
所以,更合理的做法是:
将所有商品共有的属性(如库存量、价格、商品类型等)单独保留; 将所有商品共有的属性(如库存量、价格、商品类型等)单独保留; 将所有商品共有的属性(如库存量、价格、商品类型等)单独保留;
将不同商品各自特有的属性组织在一起(结构体) 将不同商品各自特有的属性组织在一起(结构体) 将不同商品各自特有的属性组织在一起(结构体)
再利用(联合体)来存放这些同一时刻只会使用其中一种的成员 再利用(联合体)来存放这些同一时刻只会使用其中一种的成员 再利用(联合体)来存放这些同一时刻只会使用其中一种的成员
我再来画图精简说法: 我再来画图精简说法: 我再来画图精简说法:

代码实现: 代码实现: 代码实现:
c
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;
};
代码的结构示意图如下: 代码的结构示意图如下: 代码的结构示意图如下:

1.5 联合的一个练习
写⼀个程序,判断当前机器是⼤端?还是⼩端?
c
#include <stdio.h>
int check_system()
{
union Un
{
int i;
char c;
}un;
un.i = 1;
return un.c;
}
int main()
{
int c = check_system();
if (c == 1)
printf("小端\n");
else
printf("大端\n");
return 0;
}
画图演示: 画图演示: 画图演示:

2. 枚举类型
2.1 枚举类型的声明
枚举就是把一组可能的取值集中列出来 ,表示某个变量只能在这些固定值中选择 (一一列举)。
例如:
一周的星期:星期一到星期日,共 7 个值,可以用枚举表示。
性别:男、女、保密,也可以用枚举表示。
月份:1 月到 12 月,也可以用枚举表示。
三原色:红、绿、蓝,也可以用枚举表示。
这些数据就可以用枚举来表示:
c
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
enum Color//颜⾊
{
RED,
GREEN,
BLUE
};
上面的enum Day,enum Sex,enum Color 都是枚举类型 。
枚举大括号{}中列出的内容是该枚举类型的所有可能取值,这些取值叫做枚举常量。
枚举常量本质上都有对应的整数值:
- 默认从零开始
- 后面的值依次加1
- 定义枚举时,也可以手动给枚举常量赋值。
c
enum Sex
{
//枚举类型的可能取值 - 枚举常量
MALE, //0
FEMALE, //1
SECRET //2
};
enum Color
{
//赋值
RED = 1,
GREEN = 3,
BLUE = 5
};

2.2 枚举类型的优点
| 优点 | 简单说明 |
|---|---|
| 提高代码可读性 | 用有意义的名字表示固定取值,代码更容易理解 |
| 便于维护 | 相关常量集中定义,修改和管理更方便 |
| 有类型约束 | 相比 #define,枚举属于一种类型,使用更规范 |
| 便于调试 | 枚举常量在调试时更容易识别含义 |
| 可一次定义多个常量 | 可以把一组相关取值统一放在一个枚举中 |
| 遵循作用域规则 | 枚举定义在某个作用域内时,只能在对应作用域中使用 |
2.3 枚举类型的使用
c
enum Color//颜⾊
{
RED=1,
GREEN=2,
BLUE=4
};
enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值
注意,在C++中,用整数给枚举常量赋值是不行的,一个是整型类型,一个是枚举类型,但是在C语言中是可以这样赋值的。
