自定义类型:联合和枚举

目录

  • [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 联合体大小的计算

由于联合体大小的计算需要涉及到内存对齐 的相关知识点,所以读者可以在自定义类型:结构体中进行学习。

联合体大小计算规则 : 联合体大小计算规则: 联合体大小计算规则:

  1. 联合体的大小至少等于 最大成员的大小。

  2. 为满足内存对齐 要求,联合体的总大小 通常需要是最大对齐数整数倍 ;如果不是,则会自动填充到对应的整数倍。

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 Dayenum Sexenum 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语言中是可以这样赋值的。

相关推荐
Zhang~Ling1 小时前
C++ 继承机制详解下:多继承、虚继承与菱形继承底层原理
开发语言·c++·算法
思麟呀1 小时前
C++工业级日志项目(四)日志落地
linux·开发语言·c++·windows
小熊Coding1 小时前
Python二手图书市场行为分析系统
开发语言·爬虫·python·django·计算机毕业设计·数据可视化分析·二手图书分析系统
搬砖的小码农_Sky1 小时前
macOS Sequoia上如何安装gcc/g++环境?
c语言·c++·macos
MC皮蛋侠客1 小时前
C++17 多线程系列(二):共享数据与同步——mutex 与 condition_variable
开发语言·c++·多线程
愈努力俞幸运1 小时前
python 三引号
android·开发语言·python
止语Lab2 小时前
Go跨平台编译的决策树:从\
开发语言·决策树·golang
Das12 小时前
【408】C语言标识符
c语言·开发语言
zxd0203112 小时前
DevOps + CI/CD:从理念到 Jenkins 实战落地
java·开发语言