重生之我在异世界学编程之C语言:枚举联合篇

news2025/1/10 12:54:20

大家好,这里是小编的博客频道
小编的博客:就爱学编程

很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!

本文目录

  • 引言
  • 正文
    • 枚举(Enum)
      • 1.枚举的定义和基本使用
      • 2.枚举的优点
      • 3.枚举的使用场景
      • 4.枚举与switch语句
    • 联合(Union)
      • 1.联合的定义和基本使用
      • 2.联合与内存对齐
        • (1)联合体大小
        • (2)联合体内存分配
      • 3.联合的使用场景
      • 4.联合的优点
    • 枚举和联合的高级使用
      • 1.枚举的位字段
      • 2.联合的类型转换
      • 3.枚举和联合的组合使用
      • 4.注意事项
  • 快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

引言

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语言中的重要性和灵活性。它们为程序员提供了强大的工具,以处理各种复杂的数据类型和内存管理问题。正确使用枚举和联合可以显著提高程序的性能和可维护性。

快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2274343.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6 分布式限流框架

限流的作用 在API对外互联网开放的情况下&#xff0c;是无法控制调用方的行为的。当遇到请求激增或者黑客攻击的情况下&#xff0c;会导致接口占用大量的服务器资源&#xff0c;使得接口响应效率的降低或者超时&#xff0c;更或者导致服务器宕机。 限流是指对应用服务进行限制…

【Linux系列】如何使用 nohup 命令在后台运行脚本

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

门禁系统与消防报警的几种联动方式

1、规范中要求的出入口系统与消防联动 1.1《建筑设计防火规范》GB 50016-2018 1.2《民用建筑电气设计规范》JGJ 16-2008  14.4出入口控制系统 3 设置在平安疏散口的出入口限制装置&#xff0c;应与火灾自动报警系统联动;在紧急状况下应自动释放出入口限制系统&…

Express 加 sqlite3 写一个简单博客

例图&#xff1a; 搭建 命令&#xff1a; 前提已装好node.js 开始创建项目结构 npm init -y package.json:{"name": "ex01","version": "1.0.0","main": "index.js","scripts": {"test": &q…

GetMaterialApp组件的功能与用法

文章目录 1. 知识回顾2. 使用方法2.1 源码分析2.2 常用属性3. 示例代码4. 内容总结我们在上一章回中介绍了"Get包简介"相关的内容,本章回中将介绍GetMaterialApp组件.闲话休提,让我们一起Talk Flutter吧。 1. 知识回顾 我们在上一章回中已经介绍过GetMaterialApp组…

LabVIEW之树形控件

一、树形控件基本构成 树形控件这个名称非常形象&#xff0c;其如同树一样&#xff0c;是典型的分层结构。树形控件的属性和方法使用非常灵活&#xff0c;树形控件的内容既可以静态编辑&#xff0c;也可以通过编程来动态填充。静态编辑树形控件适用于内容不变的应用场景&#…

Inno Setup制作安装包,安装给win加环境变量

加 ; 加环境变量&#xff0c;开启&#xff0c;下面一行 ChangesEnvironmentyes 和 ; 加环境变量wbrj变量名&#xff0c;{app}\project\bin变量值&#xff0c;{app}\后接文件名&#xff0c;{app}表示安装路径。下面一行,{olddata};原来的值上拼接 Root: HKLM; Subkey: “SYSTEM\…

张朝阳惊现CES展,为中国品牌 “代言”的同时,或将布局搜狐新战略!

每年年初&#xff0c;科技圈的目光都会聚焦在美国拉斯维加斯&#xff0c;因为这里将上演一场被誉为 “科技春晚” 的年度大戏 ——CES 国际消费电子展。作为全球规模最大、最具影响力的科技展会之一&#xff0c;CES 吸引了来自 160 多个国家的创新者和行业领导者&#xff0c;是…

UDS诊断之0x27服务—结合实例讲解

前言&#xff1a; 本文讲解的是比较深入一点知识&#xff0c;对于一些刚入门的同学&#xff0c;建议直接先看一遍14229规范&#xff0c;然后找一个实际项目练练手&#xff01;然后再来看本文&#xff0c;相信你会对0x27服务有更深的认知&#xff01;&#xff01;&#xff01; …

React Router 向路由组件传state参数浏览器回退历史页面显示效果问题

昨天在看尚硅谷张天禹老师讲的 React教程p90&#xff0c;老师讲到 React路由的 replace模式和push模式&#xff0c;老师的演示效果与自己本地操作不太一样。 老师的效果&#xff1a;点击查看消息1&#xff0c;消息2&#xff0c;消息3 再点回退&#xff0c;可以依次查看到 消息…

静态路由配置与调试——计算机网络实训day1

文章目录 操作前准备一、实验目的二、实验要求三、实验过程1、在R1和R2上配置设备名称。基本配置设备命名 2、在R1和R2上配置接口IP地址&#xff0c;并查看IP地址的配置情况。3、在R1和R2上配置静态路由&#xff0c;并查看路由表。静态路由缺省路由&#xff08;默认路由&#x…

【HeadFirst系列之HeadFirst设计模式】第1天之HeadFirst设计模式开胃菜

HeadFirst设计模式开胃菜 前言 从今日起&#xff0c;陆续分享《HeadFirst设计模式》的读书笔记&#xff0c;希望能够帮助大家更好的理解设计模式&#xff0c;提高自己的编程能力。 今天要分享的是【HeadFirst设计模式开胃菜】&#xff0c;主要介绍了设计模式的基本概念、设计模…

UOS系统和windows系统wps文档显示差异问题解决

最近在使用UOS系统的过程中&#xff0c;发现了一个很有意思的现象。就是在UOS系统上编辑的文档&#xff0c;发到windows系统上&#xff0c;会出现两个文档显示差异很大的情况&#xff0c;文档都是使用一样的wps软件打开的。到底是什么原因导致这种现象的呢&#xff1f;该如何解…

网络应用层HTTP协议

网络应用层HTTP协议 1. HTTP协议介绍 在互联网世界中&#xff0c;HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信&#xff0c;以交换或传输超文本(如 HTML 文档)。…

B+树的原理及实现

文章目录 B树的原理及实现一、引言二、B树的特性1、结构特点2、节点类型3、阶数 三、B树的Java实现1、节点实现2、B树操作2.1、搜索2.2、插入2.3、删除2.4、遍历 3、B树的Java实现示例 四、总结 B树的原理及实现 一、引言 B树是一种基于B树的树形数据结构&#xff0c;它在数据…

在 macOS 中,设置自动将文件夹排在最前

文章目录 1、第一步访达设置2、第二步排序方式 需要两步设置 1、第一步访达设置 按名称排序的窗口中 2、第二步排序方式 选择名称

【数据库】Unity 使用 Sqlite 数据库

1.找到需要三个 DLL Mono.Data.Sqlite.dllSystem.Data.dllsqlite3.dll 上面两个dll可在本地unity安装目录找到&#xff1a; C:\Program Files\Unity\Hub\Editor\2022.3.xxf1c1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit-win32 下面dll可在sqlite官网下载到&#xff…

国内使用博查SearchAPI进行智能搜索,通过API获取搜索引擎的天气、日历、百科、手机、火车票等信息

在现代开发中&#xff0c;网络资源搜索是关键且常见的需求。博查SearchAPI作为国内领先的智能搜索解决方案&#xff0c;已服务超过2000家企业和16000名开发者&#xff0c;获得腾讯元器、字节扣子、阿里钉钉等官方推荐。该API提供近百亿网页内容及多样的生态合作内容&#xff0c…

免费网站源码下载指南:如何安全获取并降低开发成本

许多开发者或是需要建立网站的人&#xff0c;可以方便地获取免费网站源码。这样的下载能帮助他们降低开发费用&#xff0c;迅速构建起基本框架。但在此过程中&#xff0c;仍有许多需要注意的事项。 许多开发者或是需要建立网站的人&#xff0c;可以方便地获取免费网站源码。这…

colnames看似简单,却能优化数据处理流程

引言 在数据处理和分析中&#xff0c;变量名称是至关重要的&#xff0c;它们决定了数据的可读性和操作的简便性。在R语言中&#xff0c;colnames 函数以其简单的语法设计&#xff0c;提供了高效管理数据框列名的能力&#xff0c;尤其是在复杂的爬虫任务中显得尤为重要。本篇文…