目錄
前言
一、聯合體(共用體)
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; }