当前位置: 首页 > news >正文

联合体和枚举——嵌入式学习笔记

目录

前言

一、联合体(共用体)

1、基本概念

2、初始化和引用

(1)初始化

(2)引用

二、枚举


前言

        在C语言的编程世界中,我们早已熟悉了结构体struct这种能将不同数据类型捆绑在一起的“打包”神器。但你是否想过,如果有一块内存,可以灵活地存放不同类型的数据,但在同一时刻只使用其中一种,该如何实现?又是否曾为那些 magic number(魔法数字)和意义不明的整数常量而头疼?

        这就是联合体(union)和枚举(enum)大显身手的地方。它们一个是高效利用内存的“变体”专家,一个是提升代码可读性与安全性的“语义化”大师。本篇博客将带你深入浅出,探索这两个强大工具的奥秘,让你的C代码更加专业、优雅和高效。


一、联合体(共用体)

1、基本概念

说明:

        联合体的外在形式跟结构体非常相似,但它们有一个本质的区别:结构体中的各个成员各自独立,而联合体的各个成员却共用一块内存,因此联合体也称为共用体

图解:

        

特点:

        整个联合体变量的尺寸,取决于联合体尺寸最大的成员

        给联合体的某个成员赋值,会覆盖其他成员,使它们失效

        

        联合体各成员之间形成一个 "互斥"的逻辑的,在某一个时刻只有一个成员有效

语法:

        联合体标签:用来区分各个不同的联合体

        成员: 是包含在联合体内部的数据,可以是任意的数据类型

基本结构:

union 联合体标签
{成员1;成员2;...        
};

2、初始化和引用

(1)初始化

说明:

        联合体的操作跟结构体形式上别无二致,但由于联合体特殊的存储特性,不管怎么初始化和赋值,最终有且仅有一个成员是有效的

示例代码:

        

#include <stdio.h>union node1
{char ch;        // A、B、C、Dint num;        // 60、70、80、90、100double f;       // 99.9、59.9char buf[128];  // 优秀、良好、中等、及格、差
};union node2
{char ch;        // A、B、C、Dint num;        // 60、70、80、90、100
};// 主函数
int main(int argc, char const *argv[])
{// (1)、联合体的初始化// 1、普通初始化union node1 n1 = {'A', 90, 99.9, "优秀"};printf("联合体成员的值 == %d\n",  n1.ch);printf("n1的大小为    == %lu\n", sizeof(n1));   // - 整个联合体变量的尺寸,取决于联合体尺寸最大的成员/*报警告:warning: excess elements in union initializer// 翻译:警告:联合体初始化器中的元素过多原因:只有第一个成员有效,其它成员赋值无效,也无需赋值- 给联合体的某个成员赋值,会覆盖其他成员,使它们失效- 联合体各成员之间形成一个 "互斥"的逻辑的,在某一个时刻只有一个成员有效*/// 2、指定成员初始化(只有最后一个赋值有效,其它赋值无效,会被覆盖)union node2 n2 ={.num = 80,.ch  = 'D'};printf("联合体的成员的值 == %c\n", n2.ch);printf("联合体的成员的值 == %d\n", n2.num);printf("n2的大小为      == %lu\n", sizeof(n2));return 0;
}

(2)引用

说明:

        联合体一般很少单独使用,而经常以结构体的成员形式存在,用来表达某种互斥的属性

示例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>union node1
{char ch;        // A、B、C、Dint num;        // 60、70、80、90、100double f;       // 99.9、59.9char buf[128];  // 优秀、良好、中等、及格、差
};union node2
{char ch;        // A、B、C、Dint num;        // 60、70、80、90、100
};typedef struct student       
{char name[128];     char phone[128];int id;int gender;char class[128];float height;float weight;int age;union node1 score;   // 里面有四种互斥的属性}stu_t, *stu_p;         // 主函数
int main(int argc, char const *argv[])
{// (1)、联合体的初始化// 1、普通初始化union node1 n1 = {'A', 90, 99.9, "优秀"};printf("联合体成员的值 == %d\n",  n1.ch);printf("n1的大小为    == %lu\n", sizeof(n1));   // - 整个联合体变量的尺寸,取决于联合体尺寸最大的成员/*报警告:warning: excess elements in union initializer// 翻译:警告:联合体初始化器中的元素过多原因:只有第一个成员有效,其它成员赋值无效,也无需赋值- 给联合体的某个成员赋值,会覆盖其他成员,使它们失效- 联合体各成员之间形成一个 "互斥"的逻辑的,在某一个时刻只有一个成员有效*/// 2、指定成员初始化(只有最后一个赋值有效,其它赋值无效,会被覆盖)union node2 n2 ={.num = 80,.ch  = 'D'};printf("联合体的成员的值 == %c\n", n2.ch);printf("联合体的成员的值 == %d\n", n2.num);printf("n2的大小为      == %lu\n", sizeof(n2));// (2)、联合体的引用// 1、联合体的直接引用(最后的赋值,会将整个联合体全部覆盖)n1.ch   = 'C';n1.num  = 120;n1.f    = 59.9;strcpy(n1.buf , "优秀+");printf("n1.buf == %s\n", n1.buf);// 2、联合体的间接引用(最后的赋值,会将整个联合体全部覆盖)union node1 *p1 = &n1;                          // 指针指向的内存的是栈区union node1 *p2 = malloc(sizeof(union node1));  // 指针指向的内存的是堆区(无初始化)bzero(p2, sizeof(union node1));// 栈区指针strcpy(p1->buf, "良好");p1->ch  = 'E';p1->num = 220;p1->f   = 6.28;printf("p1->f == %f\n", p1->f);// 堆区指针strcpy(p2->buf, "中等");p2->num = 330;p2->f   = 12.56;p2->ch  = 'F';printf("p2->f == %c\n", p2->ch);// (3)、联合体的实际的引用例子struct student stu1 = {0};stu1.score.num = 100;       /*此处可以选择一下四种评价标准,但同一时间内只能够选择其中一种ch;      // A、B、C、Dnum;     // 60、70、80、90、100f;       // 99.9、59.9;        // 优秀、良好、中等、及格、差*/return 0;
}


二、枚举

说明:

        枚举类型的本质是提供一种范围受限的类型,比如用0-6表示7种颜色,用0-3表示4种状态,但枚举在C语言种并未实现其本来应用的效果,直到C++才拥有原本该有的属性

        是使用有意义的单词,来代替无意义的数字,提高程序的可读性...

语法:

        enum是关键字

        spectrum是枚举常量列表标签,省略的情况下无法定义枚举变量

格式:

enum 枚举常量列表标签
{常量1,常量2,...
}

例子:

// 枚举类型
enum color{red, orange, yellow=8, green, blue, cyan, purple};
enum {reset, running, sleep, stop};// 枚举变量
enum color c = yellow;    // 等价于c = 2

要点:

        枚举常量实质上就是整型,首个 枚举常量默认为0

        枚举常量在定义时可以赋值,若不赋值,则取值前面的枚举常量的值加1

        C语言种,枚举等价于整型,支持整型数据的一切操作

示例代码:

#include <stdio.h>// stm32的枚举的使用(相比define的好处是可以归类,并且可以迅速且大规模的铺开)
typedef enum IRQn
{/******  Cortex-M4 Processor Exceptions Numbers ****************************************************************/NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                                          */MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M4 Memory Management Interrupt                           */BusFault_IRQn               = -11,    /*!< 5 Cortex-M4 Bus Fault Interrupt                                   */UsageFault_IRQn             = -10,    /*!< 6 Cortex-M4 Usage Fault Interrupt                                 */SVCall_IRQn                 = -5,     /*!< 11 Cortex-M4 SV Call Interrupt                                    */DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M4 Debug Monitor Interrupt                              */PendSV_IRQn                 = -2,     /*!< 14 Cortex-M4 Pend SV Interrupt                                    */SysTick_IRQn                = -1,     /*!< 15 Cortex-M4 System Tick Interrupt                                *//******  STM32 specific Interrupt Numbers **********************************************************************/// ...
}IRQn_Type;// 表示颜色
enum color      // 有标签,所以能定义变量
{red,        // 没有赋值默认为0(后面的值依次+1)orange,     // 1yellow,     // 2green=8,    // 如果赋值了,那么从此数据开始,后面依次+1(前面数据依然遵循前面的规则)blue,       // 9cyan,       // 10   purple      // 11
};
enum            // 没有标签,所以不能定义变量
{reset,      // 重启running,    // 运行sleep,      // 休眠stop        // 停止,关机
};// 主函数
int main(int argc, char const *argv[])
{// (1)、枚举类型默认初始化和引用enum color c = 1;c = c + 1;printf("c == %d\n", c); // 枚举等价于整型,支持整型数据的一切操作1// (2)、在实际开发种使用(是使用有意义的单词,来代替无意义的数字,提高程序的可读性...)// 枚举等价于整型,支持整型数据的一切操作2// 1、颜色选择enum color c_num = 0;printf("请选择颜色:\n");printf("0、红色\n");printf("1、橙色\n");printf("2、黄色\n");scanf("%d", (int*)&c_num);  while(getchar()!='\n');switch (c_num){case red:printf("我是红红!\n");break;case orange:printf("我是橙橙!\n");break;case yellow:printf("我是黄黄!\n");break;}// 2、机器状态选择同上return 0;
}

http://www.dtcms.com/a/358753.html

相关文章:

  • 每日算法题【二叉树】:二叉树的最大深度、翻转二叉树、平衡二叉树
  • 【系统分析师】高分论文:论软件的系统测试及应用
  • 栈溢出问题
  • Redis-数据类型的常用操作命令
  • uart学习
  • Jdk动态代理 Cglib动态代理
  • MYSQL表结构优化场景
  • 解构机器学习:如何从零开始设计一个学习系统?
  • folium地图不显示加载不出来空白问题解决
  • SAP PP模块的MPS
  • 福彩双色球第2025100期篮球号码分析
  • git在push和clone等操作时显示‘: Invalid argument
  • 优选算法:二分查找
  • #5:Nginx核心使用技术
  • Java 学习笔记(基础篇12)
  • 小狼毫输入法中让数字键盘上的数字键不再选择候选词而是与原始输入一起直接上屏
  • 计算机视觉与深度学习 | 基于深度学习的图像特征提取与匹配算法综述及MATLAB实现
  • 互联网大厂大模型应用开发岗位面试:技术点详解与业务场景演练
  • nacos3端口漂移问题
  • shell编程-核心变量知识
  • LeetCode - 234. 回文链表
  • 2025年高性能计算年会
  • Golang 面试题「高级」
  • 零碳智慧园区双碳方案
  • 代理IP网站哪家好?全球优质IP代理服务商有什么推荐?
  • 【Linux】网络安全管理:Netfilter、nftables 与 Firewalld | Redhat
  • Linux查看Java进程PID、端口号和内存占用脚本
  • 2023年山东省信息学小学组(CSP-X)第一轮题解
  • 【嵌入式原理系列-第六篇】从Flash到RAM:MCU ld脚本全解析
  • SUMO 与 孪易 IOC 协同:开启交通数字孪生新纪元