C 语言联合与枚举:自定义类型的核心解析

目录

1.联合体

1.1联合体的声明与创建

1.2联合体在内存中的存储

1.3相同成员的结构体与内存比较

1.4联合体内存空间大小的计算

1.5联合体的应用

2.枚举类型

2.1枚举变量的声明

2.2枚举变量的优点

2.3枚举的使用


上篇博客中,我们通过学习了解了C语言中一种自定义类型结构体的相关知识,那么该语言中是否还拥有相似的自定义类型呢?这将是我们今天学习的目标。


1.联合体

联合体其实跟结构体类似,也是由一个或多个成员构成,这些成员可以是不同类型。

以下是联合体的定义:

在C语言中,联合体(Union)是一种特殊的数据结构,允许在同一内存位置存储不同的数据类型。


1.1联合体的声明与创建

cpp 复制代码
union un {
	int n;
	char ch;
};

int main()
{
	//声明
	union un u1;

	union un* pu = &u1;

	u1.ch = 'w';
	printf("%c\n", u1.ch);
	printf("%c\n", pu->ch);
	u1.n = 5;
	printf("%d\n", u1.n);
	printf("%d\n", pu->n);
	return 0;
}

我们在上面的代码中可以看到,联合体和结构体有非常多类似的地方,创建,声明,访问成员变量都很相似。


1.2联合体在内存中的存储

编译器在为联合体分配内存时,并不会像结构体一样为每个成员变量都分配内存,它只会分配在内存中占用最大空间的成员变量的空间,其他变量将会于该变量共用这一块空间,所以联合体又叫共用体。所以有一点要注意:给联合体其中一个变量赋值,其他成员的值往往也会跟着变化。

从第一个代码的结果我们可以发现:联合体本身和联合体的成员变量的首个字节地址时相同的。第二个代码我们分别给变量 i 和 c 赋值,发现 i 的结果会被 c 的赋值给覆盖掉,画出它们的内存布局图:


1.3相同成员的结构体与内存比较

cpp 复制代码
struct S
{
	char c;
	int i;
};

struct S s = { 0 };


union Un
{
 char c;
 int i;
};
union Un un = { 0 };

我们画出它们的内存空间图进行比较:

我们可以看到,结构体的每个成员都有自己的内存空间,而联合体中 i 和 c 共工用一块空间的。

1.4联合体内存空间大小的计算

在前面我们说过,编译器只会分配联合体在内存中占用最大空间的成员变量的空间,其实这是不全面的,他还有以下两条规则:

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

我们看下面代码:

第一个联合体un1内部有两个变量,一个是char型数组,一个是 int 类型,计算字符型数组的对齐数时,我们并不会将它的对齐数看作5,而是将其与char类型一样看待,所以他的对齐数是1,而整型类型的对齐数是4,所以un1的对齐数为4,但是该联合体最大成员大小是5,所以该联合体大小为8。

第一个联合体un2内部也是两个变量,一个是short类型数组,一个是int类型,计算short型数组的对齐数时,也是一样的规则,将其与short类型一样看待,所以他的对齐数是2,而整型类型的对齐数是4,所以un1的对齐数为4,但是该联合体最大成员大小是34,所以该联合体大小为36。

1.5联合体的应用

使用联合体时,因为给它分配的内存空间要少于同样类型结构体,所以使用联合体是要更节省空间的,我们来句一个例子。

我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。 每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

图书:书名、作者、⻚数

杯⼦:设计

衬衫:设计、可选颜⾊、可选尺⼨

我们不加思索,直接写出结构体:

cpp 复制代码
struct gift_list
{
	int stock_number;//库存量
	double price;//价格
	int item_type;//商品类型

	char title[20];//书名
	char author[20];//作者
	int num_pages;//页数

	char design[30];//设计
	int color;//颜色
	int szie;//尺寸
};

上述的结构其实设计的很简单,⽤起来也⽅便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的⼤⼩就会偏⼤,⽐较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常⽤的。⽐如: 商品是图书,就不需要design、colors、sizes。

所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使⽤联合体起来,这样就可以介绍所需的内存空间,⼀定程度上节省了内存。

cpp 复制代码
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];//设计
		}cup;

		struct
		{
			char design[30];//设计
			int color;//颜色
			int szie;//尺寸
		}shirt;
	}item;
};

下面我们再来做一个熟悉的练习,写一个程序,判断当前机器是大端还是小端?为什么说熟悉呢?因为我们在之前的博客里已经讲过这道题了,之前我们时这样做的:

cpp 复制代码
int main()
{
	int n = 1;
	int* ps = &n;
	if (*((char*)ps) == 1)
		printf("小端");
	else
		printf("大端");
	return 0;
}

之前我们是用了强制转换来这道题的,学习了联合体后,我们有没有其他的思路呢?看下面代码:

cpp 复制代码
union
{
	int i;
	char c;
}un;

int main()
{
	un.i = 1;
	if (un.i == 1)
		printf("小端");
	else
		printf("大端");
	return 0;
}

这个代码利用了联合体内变量共用同一块内存,如果是小端存储模式,将i赋值为1,那么c也会被赋值为1,如果没有,则证明是大端存储模式。

2.枚举类型

2.1枚举变量的声明

枚举顾名思义就是⼀⼀列举。
把可能的取值⼀⼀列举。
⽐如我们现实⽣活中:
⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举
性别有:男、⼥、保密,也可以⼀⼀列举
⽉份有12个⽉,也可以⼀⼀列举
三原⾊,也是可以意义列举
这些数据的表⽰就可以使⽤枚举了。

cpp 复制代码
enum Month
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

enum Sex
{
	male,
	female,
	secret,
};

enum Color
{
	red,
	green,
	blue
};

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。

{}中的内容是枚举类型的可能取值,也叫 枚举常量 。
这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

cpp 复制代码
//默认
enum Color
{
	red = 0,
	green = 1,
	blue = 2
};

enum Color
{
	red = 1,
	green = 5,
	blue = 9
};

2.2枚举变量的优点

我们可以使⽤ #define 定义常量,为什么⾮要使⽤枚举?
枚举的优点:

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

2.3枚举的使用

cpp 复制代码
enum Color//颜⾊
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值

那是否可以拿整数给枚举变量赋值呢?在C语⾔中是可以的,但是在C++是不⾏的,C++的类型检查⽐较严格。

相关推荐
Enougme2 分钟前
python-图片分割
开发语言·python
sunbyte12 分钟前
Three.js + React 实战系列-3D 个人主页 :完成 Navbar 导航栏组件
开发语言·javascript·react.js
诺亚凹凸曼15 分钟前
Java基础系列-LinkedList源码解析
java·开发语言
Maỿbe19 分钟前
手动实现LinkedList
java·开发语言
eli96035 分钟前
LIB-ZC, 一个跨平台(Linux)平台通用C/C++扩展库, 网络socket
linux·c语言·c++
6329736 分钟前
树莓派3B的外网访问
开发语言·php
czxyvX39 分钟前
016-C语言内存函数
c语言
Delphi菜鸟41 分钟前
go环境安装mac
开发语言·后端·golang
The Chosen One9851 小时前
C++:详解命名空间
开发语言·c++
一只鱼^_1 小时前
第 28 场 蓝桥月赛
开发语言·数据结构·c++·算法·面试·蓝桥杯