C语言自定义类型:联合和枚举

1. 联合体

1.1 联合体类型的声明

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以不同的类型。

但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体。

给联合体其中一个成员赋值,其他成员的值也跟着变化

c 复制代码
#include <stdio.h>
//联合类型的声明
union Un
{
	char c;//占1字节
	int i; //占4字节
};
int main()
{
	//联合变量的定义
	union Un un = {0};
	//计算连个变量的⼤⼩
	printf("%zd\n", sizeof(un));
	return 0;
} 

1.2 联合体的特点

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

先来看一段代码:

c 复制代码
#include <stdio.h>
union Un
{
	char c;//占1字节
	int i; //占4字节
};
int main()
{
	union Un un = {0};
	printf("%zd\n", sizeof(un));
	printf("%p\n",&un);
	printf("%p\n",&(un.i));
	printf("%p\n",&(un.c));
	return 0;
} 

运行发现:

开辟了4个字节的空间 u 的地址/ u.i / u.c的地址是一样的 c 和 i 共用了一块空间 ,这样就导致对 c 修改会改变 i ,对 i 修改也是同理因为他们共用了一块空间所以同一时间只能有效使用一个成员。

总结一下联合体的特点:

1. 共用体大小 = 最大成员的大小(本例为 4 字节)
2. 共用体所有成员共享同一块内存,地址完全相同
3. 同一时间只能有效使用一个成员

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

结构体:

c 复制代码
#include <stdio.h>
struct S
{
	char c;
	int i;
};
	struct S s = {0};


联合体:

c 复制代码
#include <stdio.h>
union Un
{
	char i;
	int i;
};
union Un un = {0};


总结:

1.4 联合体大小的计算

计数规则:

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

c 复制代码
#include <stdio.h>
union Un1
{
	char c[5];//char类型占1字节    对齐数为1
	int i;    //int类型占4字节     对齐数为4
	//联合的大小至少是最大成员(5)的大小
	//对齐到最大对齐数(4)的整数倍
};
union Un2
{
	short c[7];//short类型占2字节    对齐数为2
	int i;     //int类型占4字节      对齐数为4
	//联合的大小至少是最大成员(14)的大小
	//最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数(4)的整数倍
};
int main()
{
	//下⾯输出的结果是什么?
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

联合体的一个练习:
写一个程序,判断当前机器是大端?还是小端?

我们在之前的章节中实现过这个代码现在来回顾一下:

c 复制代码
#include <stdio.h>
int check_sys()
{
	int n = 1;
	return *(char*)&n;
}
int main()
{
	int ret = check_sys();//小端返回:1,大端返回:0
	if(ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

使用联合体实现:

c 复制代码
#include <stdio.h>
int check_sys()
{
	union Un
	{
		char c;
		int i;
	}u;
	u.i = 1;
	return u.c;
}
int main()
{
	int ret = check_sys();//小端返回:1,大端返回:0
	if(ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

在小端模式下,整数 1 的低位字节(0x01)存储在低地址,而 char c 读取的正是这个低地址字节,因此返回 1
在大端模式下,整数 1 的高位字节(0x00)存储在低地址,char c 读取的是 0,因此返回 0

核心巧妙之处:利用联合体共享内存的特性

c 和 i 共用开头 1 个字节
给 i 赋值,直接能通过 c 读到第一个字节的数据

2. 枚举类型

2.1 枚举类型的声明

枚举顾名思义就是一个一个列举,把可能值全部列举出来。

比如:

一周的星期一到星期日是有限的7天,可以⼀⼀列举
性别有:男、女、保密,也可以一一列举
月份有12个月,也可以一一列举

c 复制代码
#include <stdio.h>
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都是枚举类型,{ } 中的内容是枚举类型可能的取值,也叫枚举常量。
这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

c 复制代码
enum Color//颜⾊
{
	RED=2,
	GREEN=4,
	BLUE=8
};

2.2 枚举类型的使用

举例:计算器菜单选择程序,用枚举来表示菜单选项:

c 复制代码
#include <stdio.h>
void menu()
{
	printf("********************\n");
	printf("***  1.add 2.sub ***\n");
	printf("***  3.mul 4.div ***\n");
	printf("***    0.exit    ***\n");
	printf("********************\n");

}
enum Option
{
	exit,//0
	add,//1
	sub,//2
	mul,//3
	div//4
};


int main()
{
	int input = 0;
	printf("请选择:>");
	scanf("%d",&input);
	switch (input)
	{
	case add: // 直接用枚举名,不用记数字!
		break;
	case sub:
		break;
	case mul:
		break;
	case div:
		break;
	case exit:
		break;
	default:
		break;
	}
	return 0;
}

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

相关推荐
计算机安禾2 小时前
【数据结构与算法】第34篇:选择排序:简单选择排序与堆排序
c语言·开发语言·数据结构·c++·算法·排序算法·visual studio
ん贤2 小时前
Go 并发高频十问:goroutine 与线程的区别是什么?select 底层原理是什么?
开发语言·golang·并发
星晨雪海3 小时前
企业标准 DTO 传参 + Controller + Service + 拷贝工具类完整版
java·开发语言·python
龙侠九重天3 小时前
C# 机器学习数据处理
开发语言·人工智能·机器学习·ai·c#
IT 行者8 小时前
Web逆向工程AI工具:JSHook MCP,80+专业工具让Claude变JS逆向大师
开发语言·javascript·ecmascript·逆向
程序员 沐阳10 小时前
JavaScript 内存与引用:深究深浅拷贝、垃圾回收与 WeakMap/WeakSet
开发语言·javascript·ecmascript
Mr_Xuhhh10 小时前
Java泛型进阶:从基础到高级特性完全指南
开发语言·windows·python
汀、人工智能10 小时前
[特殊字符] 第40课:二叉树最大深度
数据结构·算法·数据库架构·图论·bfs·二叉树最大深度
沉鱼.4410 小时前
第十二届题目
java·前端·算法