大家好,这里是小编的博客频道
小编的博客:就爱学编程
很高兴在CSDN这个大家庭与大家相识,盼望能在这里与大家共同进步,共同收获更好的自己!!!
引言
C语言中的罗列(Enum)和团结(Union)是两种强大的数据结构,它们在程序计划中饰演侧重要角色。罗列提供了一种界说命名常量的方式,使得代码更加清晰和易于管理。而团结则允许在相同的内存位置存储不同的数据类型,这在需要节省空间或处理不同数据格式时非常有用。那就跟着小编一起来看看吧!!!
那接下来就让我们开始遨游在知识的海洋!
正文
罗列(Enum)
1.罗列的界说和根本使用
罗列是一种用户界说的类型,它允许程序员为一组整数值界说一个名字。这使得代码更加可读和易于维护。罗列通过enum关键字界说,根本格式如下:
- enum 枚举类型名 {
- 枚举常量1,
- 枚举常量2,
- ...
- };
复制代码 假如省略罗列类型名,可以界说一个匿名罗列:
- enum {
- 枚举常量1,
- 枚举常量2,
- ...
- };
复制代码 留意:
- 罗列的每个常量都是整数,它们从0开始自动赋值,除非显式指定。
这可以用一个题目领会一下:
判断下列代码运行的结果
- #include<stdio.h>
- int main() {
- enum ENUM_A
- {
- X1,
- Y1,
- Z1 = 255,
- A1,
- B1,
- };
- enum ENUM_A enumA = Y1;
- enum ENUM_A enumB = B1;
- printf("%d %d\n", enumA, enumB);
- return 0;
- }
复制代码 宝子们可以根据留意猜一下运行结果。
好,跟着小编一起看看这个代码的运行结果:
为什么是这个结果?
原因: 罗列默认从0开始,所以X1是0,故Y1是1,给了数字后会根据数字向后推,那么Z1是255,A1是256,所以B1是257。
所以我们可以知道:
- 罗列的每个常量都是整数,它们从0开始自动赋值,若前一个罗列常量被显式指定,后面的罗列常量依次递增1。
其实我们在之前的学习已经知道:#define也可以用来界说一个常量,那C语言为什么又要创建罗列类型的语法呢?
存在即合理!罗列有着自己的独一无二的优势,这是#define无法相比的,那就让我们一起来看看吧!!!
2.罗列的优点
- (1)进步代码可读性:使用罗列可以代替硬编码的数字,使代码更易读。
我们每个优点都用一个例子来佐证一下:
- enum TrafficLight {
- RED, YELLOW, GREEN
- };
- void controlLight(enum TrafficLight light) {
- if (light == RED) {
- printf("Stop at the red light.\n");
- } else if (light == YELLOW) {
- printf("Prepare to stop at the yellow light.\n");
- } else if (light == GREEN) {
- printf("Go at the green light.\n");
- }
- }
复制代码
- (2)类型安全:罗列提供了一种类型安全的方式,防止将错误的值赋给变量。
- enum TrafficLight {
- RED, YELLOW, GREEN
- };
- void controlLight(enum TrafficLight light) {
- if (light == RED) {
- printf("Stop at the red light.\n");
- } else if (light == YELLOW) {
- printf("Prepare to stop at the yellow light.\n");
- } else if (light == GREEN) {
- printf("Go at the green light.\n");
- }
- }
复制代码
- (3)便于维护:假如需要更改罗列常量的值,只需在界说处更改,而不需要搜索整个代码库。
- enum Status {
- SUCCESS = 0,
- FAILURE = 1,
- ERROR = 2
- };
- // 假设我们需要将SUCCESS的值改为1
- enum Status {
- SUCCESS = 1,
- FAILURE = 2,
- ERROR = 3
- };
复制代码 学习了以上内容,那我们再来看看罗列详细使用在哪些场景。
3.罗列的使用场景
罗列常用于表示有限的、命名的常量聚集,例如:
- 状态码(如:打开、关闭)
- 方向(如:北、南、东、西)
- 优先级(如:低、中、高)
事实上,除了以上罗列的用法,罗列还可以与swtich语句团结使用,一起来看看吧!!!
4.罗列与switch语句
- 罗列常与switch语句团结使用,处理基于不同罗列值的条件分支,进步代码的可读性和可维护性。
以下列代码为例感知:
- enum Day {
- Sunday,
- Monday,
- // ...
- };
- void printDay(enum Day day) {
- switch (day) {
- case Sunday:
- printf("Sunday");
- break;
- case Monday:
- printf("Monday");
- break;
- // ...
- }
- }
复制代码 简朴对罗列的界说与使用,进行了解后,我们再来看看团结这一节的知识。
团结(Union)
1.团结的界说和根本使用
团结是一种特殊的数据类型,允许在同一内存位置存储不同的数据类型。团结通过union关键字界说,根本格式如下:
- union 联合类型名 {
- 类型1 成员1;
- 类型2 成员2;
- ...
- };
复制代码 假如省略团结类型名,可以界说一个匿名团结:
- union {
- 类型1 成员1;
- 类型2 成员2;
- ...
- };
复制代码 留意:
- 团结的大小等于其最大成员的大小,且所有成员共享同一块内存空间。
这同样也可以用一个题目来领会一下:
判断下面代码的运行结果
- #include <stdio.h>
- union Un
- {
- short s[7];
- int n;
- };
- int main()
- {
- printf("%d\n", sizeof(union Un));
- return 0;
- }
复制代码 宝子们同样可以根据留意猜一下运行结果。
好,跟着小编一起看看这个代码的运行结果:
小编猜想很多宝子们会猜答案是14,现实的结果却是16,这似乎与我们上面说的留意相违背。
但现实上,是不违背的,因为小编另有一个知识点没有和宝子们先容:
- 现实上,团结作为一种自界说类型,它在内存中的存储也是存在对齐的。
那我们接下来就走进**团结与内存对齐**这一章的知识。
2.团结与内存对齐
团结的内存对齐取决于最大成员的对齐要求。编译器可能会对团结进行内存对齐,以进步访问服从。
内存对齐是指在创建数据结构时,按照某些规则(通常是硬件平台的要求)将数据成员存放在内存中,以进步访问服从和避免访问异常。对于团结(union)来说,内存对齐同样重要,以下是团结内存对齐规则:
数据成员对齐规则:
- 结构体或团结的数据成员,第一个数据成员存放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小的整数倍开始。
- 结构体作为成员:假如一个结构体里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。
- 结构体的总大小:即sizeof的结果,必须是其内部最大成员长度的整数倍,不敷的要补齐。
(1)团结体大小
团结体的大小取决于他所有成员中占用空间最大的一个成员的大小。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数类型的整数倍。
(2)团结体内存分配
团结体变量的各个成员都是从低字节开始公用的。即:所有的成员都是从低字节开始的。
举例阐明
示例1:考虑一个团结体,包罗一个char数组、一个int和一个float。
- union Example {
- char a[6];
- int b;
- float c;
- };
复制代码 分析:
• char a[6]占据6个字节。
• int b通常占据4个字节。
• float c通常占据4个字节。
根据团结体大小的规则,团结体的大小取决于最大成员的大小,即char a[6]的6个字节。但由于6不是4的整数倍,根据内存对齐规则,团结体的大小需要被调整为8个字节,以满足最大对齐数(通常是4或8,取决于平台)。
示例2:内嵌团结体的情况。
- union InnerUnion {
- char a[6];
- int b;
- };
- struct OuterStruct {
- short a;
- union InnerUnion uu1;
- };
复制代码 分析:
• short a占据2个字节。
• union InnerUnion uu1根据之前的表明,占据8个字节。
因此,struct OuterStruct的总大小需要是其内部最大成员长度的整数倍。在这个例子中,最大成员是union InnerUnion uu1,占据8个字节。所以,struct OuterStruct的总大小为12个字节,以满足内存对齐的要求。
通过这些规则和例子,我们可以看到:
- 团结的内存对齐是为了确保数据在内存中的存储位置符合处理器的访问要求,同时进步内存访问服从和程序性能。
3.团结的使用场景
团结常用于需要存储多种数据类型但在同一时间只能使用此中一种的场景,例如:
- 变量的多种表示情势(如:整数或浮点数)
- 内存管理(如:不同数据类型的缓冲区)
4.团结的优点
- 节省内存:由于所有成员共享内存,团结可以节省存储空间。
- union Data {
- int integer;
- float floating;
- };
- int main() {
- union Data data;
- data.integer = 10; // 使用整数存储
- // 此时,内存中存储的是整数10
- data.floating = 3.14f; // 覆盖内存,现在存储浮点数3.14
- // 此时,内存中存储的是浮点数3.14
- }
复制代码
- 进步服从:团结允许在不同数据类型之间进行高效的转换。
- union IntFloat {
- int asInt;
- float asFloat;
- };
- int main() {
- union IntFloat value;
- value.asInt = 0x40490FDB; // 以整数形式存储
- printf("As float: %f\n", value.asFloat); // 以浮点数形式读取
- }
复制代码 末了,我们再来看看罗列和团结的高级使用。
罗列和团结的高级使用
1.罗列的位字段
罗列可以与位字段团结使用,以存储多个标志位。这种方法在需要节省内存时非常有用。
- typedef enum {
- FLAG_A = 1 << 0,
- FLAG_B = 1 << 1,
- FLAG_C = 1 << 2
- } Flags;
- struct MyStruct {
- unsigned int flags : 3;
- };
- int main() {
- struct MyStruct myStruct;
- myStruct.flags = FLAG_A | FLAG_C; // 设置标志A和C
- if (myStruct.flags & FLAG_A) {
- printf("FLAG_A is set.\n");
- }
- if (myStruct.flags & FLAG_B) {
- printf("FLAG_B is set.\n");
- }
- if (myStruct.flags & FLAG_C) {
- printf("FLAG_C is set.\n");
- }
- return 0;
- }
复制代码 2.团结的类型转换
团结可以用作不同数据类型之间的转换工具。特殊是,当需要将相同内存中的数据以不同格式进行表明时,团结可以提供一种有效的方法。
- typedef union {
- float f;
- uint32_t i;
- } FloatIntUnion;
- int main() {
- FloatIntUnion data;
- data.f = 3.14159; // 设置浮点数
- // 打印浮点数及其对应的整数位模式
- printf("Float value: %.5f\n", data.f);
- printf("Integer value: 0x%08X\n", data.i);
- return 0;
- }
复制代码 3.罗列和团结的组合使用
罗列和团结可以组合使用,以创建复杂的数据结构,这些结构可以根据需要存储不同的数据类型。
- typedef enum {
- INT_TYPE,
- FLOAT_TYPE,
- STRING_TYPE
- } DataType;
- typedef union {
- int intValue;
- float floatValue;
- char *stringValue;
- } DataUnion;
- typedef struct {
- DataType type;
- DataUnion data;
- } DataHolder;
- int main() {
- DataHolder holder;
- holder.type = INT_TYPE;
- holder.data.intValue = 42;
- printf("Integer value: %d\n", holder.data.intValue);
- holder.type = FLOAT_TYPE;
- holder.data.floatValue = 3.14;
- printf("Float value: %.2f\n", holder.data.floatValue);
- holder.type = STRING_TYPE;
- holder.data.stringValue = "Hello, World!";
- printf("String value: %s\n", holder.data.stringValue);
- return 0;
- }
复制代码 4.留意事项
• 团结成员的互斥性:由于团结的所有成员共享同一块内存,因此在同一时间只能访问一个成员。修改一个成员会覆盖其他成员的数据。
• 内存对齐:编译器可能会对团结进行内存对齐,这可能会影响团结的大小和性能。
• 类型安全:虽然罗列提供了类型安全,但团结的使用可能会导致类型不安全的操作,特殊是在不同成员之间进行赋值和访问时。
通过上述详细先容:
- 我们了解罗列和团结在C语言中的重要性和灵活性。它们为程序员提供了强大的工具,以处理各种复杂的数据类型和内存管理问题。正确使用罗列和团结可以明显进步程序的性能和可维护性。
快乐的韶光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |