C語言自定義類型深度解析:聯合體與枚舉

在C語言中,自定義類型為數據組織提供了極大的靈活性。除了常用的結構體,聯合體(共用體)和枚舉也是非常重要的自定義類型。本文將結合實例,詳細解析聯合體和枚舉的特性、用法及實際應用場景。

一、聯合體(Union):共用內存的特殊類型

聯合體(又稱共用體)是一種特殊的自定義類型,它的所有成員共用同一塊內存空間,這一特性使其在內存優化場景中非常實用。

1.1 聯合體的聲明與定義

聯合體的聲明語法與結構體類似,但成員的內存布局完全不同。

// 聯合體類型聲明
union Un {char c;  // 字符型成員int i;   // 整型成員
};int main() {// 聯合體變量定義并初始化union Un un = {0}; // 計算聯合體大小printf("聯合體大小:%d\n", sizeof(un));  // 輸出結果:4return 0;
}

為什么輸出結果是4?
因為聯合體的大小至少是最大成員的大小,上述代碼中int類型成員i占4字節,因此聯合體大小為4。

1.2 聯合體的核心特點:成員共用內存

聯合體最核心的特性是所有成員共用同一塊內存空間,這意味著:

  • 聯合體變量的地址與各成員的地址相同;
  • 給一個成員賦值,可能會覆蓋其他成員的值。
實例1:驗證成員地址相同
#include <stdio.h>
union Un {char c;int i;
};int main() {union Un un = {0};// 打印聯合體變量及成員的地址printf("&un:%p\n", &un);printf("&un.i:%p\n", &un.i);printf("&un.c:%p\n", &un.c);return 0;
}

輸出結果:三個地址完全相同,證明成員共用同一塊內存。

實例2:成員賦值的相互影響
#include <stdio.h>
union Un {char c;int i;
};int main() {union Un un = {0};un.i = 0x11223344;  // 給整型成員賦值un.c = 0x55;        // 給字符型成員賦值(覆蓋低字節)printf("un.i = %x\n", un.i);  // 輸出結果:11223355return 0;
}

解析

  • int類型在內存中占4字節,0x11223344的內存布局為(假設小端存儲):44 33 22 11
  • char類型僅占1字節(低地址字節),賦值0x55后覆蓋了低字節,內存變為55 33 22 11,因此un.i最終為0x11223355

1.3 結構體與聯合體的內存布局對比

類型內存布局特點示例大小(char+int)
結構體(struct)成員按順序存儲,存在內存對齊浪費8字節(1+3對齊+4)
聯合體(union)成員共用內存,無對齊浪費4字節(取最大成員大小)

內存布局示意圖

  • 結構體:[char][3字節對齊浪費][int]
  • 聯合體:[char和int共用4字節空間]

1.4 聯合體大小的計算規則

聯合體的大小需滿足兩個條件:

  1. 至少是最大成員的大小(保證能容納最大成員);
  2. 必須是最大對齊數的整數倍(內存對齊要求)。
對齊數定義:

每個成員的對齊數 = 成員自身大小與編譯器默認對齊數(通常為8)的較小值。

實例計算:
#include <stdio.h>// 案例1:char[5]與int
union Un1 {char c[5];  // 大小5,對齊數1(char大小1)int i;      // 大小4,對齊數4(int大小4)
};// 案例2:short[7]與int
union Un2 {short c[7]; // 大小14(2*7),對齊數2(short大小2)int i;      // 大小4,對齊數4(int大小4)
};int main() {printf("Un1大小:%d\n", sizeof(union Un1));  // 輸出:8printf("Un2大小:%d\n", sizeof(union Un2));  // 輸出:16return 0;
}

計算過程

  • Un1:最大成員大小5,最大對齊數4。5不是4的倍數,向上對齊到8(4×2);
  • Un2:最大成員大小14,最大對齊數4。14不是4的倍數,向上對齊到16(4×4)。

1.5 聯合體的實用場景

場景1:節省內存空間

當不同屬性不會同時使用時,用聯合體共用內存可大幅減少內存占用。例如禮品兌換單設計:

// 優化前:結構體包含所有屬性,內存浪費
struct gift_list_old {int stock_number;  // 庫存量double price;      // 定價int item_type;     // 商品類型char title[20];    // 書名(僅圖書用)char author[20];   // 作者(僅圖書用)char design[30];   // 設計(僅杯子/襯衫用)int colors;        // 顏色(僅襯衫用)
};// 優化后:用聯合體存儲差異化屬性
struct gift_list {int stock_number;  // 公共屬性double price;      int item_type;     union {  // 差異化屬性共用內存struct { char title[20]; char author[20]; } book;  // 圖書struct { char design[30]; } mug;                    // 杯子struct { char design[30]; int colors; } shirt;      // 襯衫} item;
};
場景2:判斷機器字節序(大小端)

利用聯合體成員共用內存的特性,可簡單判斷機器存儲方式:

// 返回1:小端存儲;返回0:大端存儲
int check_sys() {union {int i;    // 4字節整型char c;   // 1字節字符} un;un.i = 1;  // 內存存儲為0x00000001(大端)或0x01000000(小端)return un.c;  // 小端返回1,大端返回0
}

二、枚舉類型(Enum):常量的有序集合

枚舉類型用于定義一組具有離散值的常量,使代碼更具可讀性和可維護性。

2.1 枚舉類型的聲明與初始化

枚舉通過enum關鍵字聲明,其中的成員稱為枚舉常量。

// 基本聲明(默認值從0開始遞增)
enum Day {Mon,   // 0Tues,  // 1Wed,   // 2Thur,  // 3Fri,   // 4Sat,   // 5Sun    // 6
};// 自定義初始值(后續值依次遞增)
enum Color {RED = 2,    // 2GREEN = 4,  // 4BLUE = 8    // 8
};

2.2 枚舉的優點:為何不用#define?

#define定義常量相比,枚舉具有明顯優勢:

  1. 增強可讀性:枚舉常量有明確的類型歸屬,代碼邏輯更清晰;
  2. 類型檢查:枚舉是強類型,編譯器會進行類型校驗(#define無類型);
  3. 便于調試:枚舉常量在調試階段可見(#define在預處理階段被替換,調試中無符號);
  4. 批量定義:一次可定義多個相關常量,無需重復寫#define
  5. 作用域規則:枚舉聲明在函數內時,僅在函數內有效,避免命名沖突。

2.3 枚舉類型的使用

枚舉變量需用枚舉常量賦值,C語言允許整數賦值但不推薦(C++嚴格禁止)。

enum Color {RED = 1,GREEN = 2,BLUE = 4
};int main() {enum Color clr = GREEN;  // 正確:用枚舉常量賦值// enum Color clr2 = 2;  // C允許,C++禁止(類型不匹配)return 0;
}

三、總結

  • 聯合體通過成員共用內存實現內存優化,適用于不同屬性不同時使用的場景,大小計算需滿足最大成員大小和對齊要求;
  • 枚舉用于定義離散常量集合,相比#define具有更強的類型安全性和可讀性,是提升代碼質量的重要工具。

合理使用聯合體和枚舉,能讓C語言代碼更高效、更易維護,尤其在嵌入式開發、內存受限場景中發揮重要作用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95054.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95054.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95054.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Numpy科學計算與數據分析:Numpy數據分析基礎之統計函數應用

Numpy統計函數實戰&#xff1a;數據的聚合與分析 學習目標 通過本課程的學習&#xff0c;學員將掌握Numpy中用于統計分析的關鍵函數&#xff0c;如求和(sum)、平均值(mean)、標準差(std)等&#xff0c;能夠熟練地在實際數據集中應用這些函數進行數據的聚合與分析。 相關知識…

從引導加載程序到sysfs:Linux設備樹的完整解析與驅動綁定機制

摘要本報告旨在為嵌入式Linux開發者詳細梳理設備樹&#xff08;Device Tree, DT&#xff09;在系統啟動中的完整解析流程。報告將從引導加載程序&#xff08;Bootloader&#xff09;如何準備和傳遞設備樹二進制文件&#xff08;DTB&#xff09;開始&#xff0c;逐步深入到內核如…

基于深度學習的污水新冠RNA測序數據分析系統

基于深度學習的污水新冠RNA測序數據分析系統 摘要 本文介紹了一個完整的基于深度學習技術的污水新冠RNA測序數據分析系統&#xff0c;該系統能夠從未經處理的污水樣本中識別新冠病毒變種、監測病毒動態變化并構建傳播網絡。我們詳細闡述了數據處理流程、深度學習模型架構、訓練…

寶塔面板配置Nacos集群

一、環境準備 準備三臺及以上的服務器&#xff0c;我這里準備了3臺服務器&#xff0c;172.31.5.123&#xff5e;125&#xff1b;分別安裝好寶塔面板&#xff0c;軟件商店里安裝nacos&#xff1b;二、Nacos集群配置 配置數據庫連接&#xff1a;? 進入每臺服務器上 Nacos 解壓后…

Spring Boot 3.x 全新特性解析

Spring Boot 是企業級 Java 開發中最常用的框架之一。自 Spring Boot 3.x 發布以來&#xff0c;其引入的一系列重大變更與優化&#xff0c;為開發者提供了更現代、更高效的開發體驗。本文將重點解析 Spring Boot 3.x 的關鍵特性及其對項目架構的影響。 一、基于 Jakarta EE 10 …

2025.8.10總結

今天晚上去跑了2公里&#xff0c;跑完還挺爽的&#xff0c;然后花了1.5個小時去公司刷題&#xff0c;沒有進行限時練&#xff0c;花了一周的時間才做完這題&#xff0c;共找了20個bug&#xff0c;雖然沒有進行限時練&#xff0c;但我仿佛對測試技術掌握得更好了&#xff0c;知道…

qt中實現QListWidget列表

使用最基本的QListWidgetItem來創建列表項&#xff0c;具體使用下面setText、setIcon、addItem這三個方法#include "mainwindow.h" #include "ui_mainwindow.h" #include "QDebug"enum CustomRoles {IdRole Qt::UserRole, // 存儲IDPhoneR…

nginx-主配置文件

nginx-主配置文件一、主配置文件nginx.conf內容二、修改配置的文件后的操作三、配置虛擬主機的域名1. 修改nignx.conf配置文件2. 新建域名對應的網頁根目錄3. 重載nginx配置4. 驗證一、主配置文件nginx.conf內容 [rootweb1 conf]# cat nginx.conf#user nobody; # nginx woke…

DBSACN算法的一些應用

以下是 DBSCAN 算法在 Python 中的幾個典型應用示例&#xff0c;涵蓋了基礎使用、參數調優和可視化等方面&#xff1a;import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import DBSCAN from sklearn.datasets import make_moons, make_blobs from skl…

java9學習筆記-part1

G1 成為默認垃圾回收器在 Java 8 的時候&#xff0c;默認垃圾回收器是 Parallel Scavenge&#xff08;新生代&#xff09;Parallel Old&#xff08;老年代&#xff09;。到了 Java 9, CMS 垃圾回收器被廢棄了&#xff0c;G1&#xff08;Garbage-First Garbage Collector&#x…

【github.io靜態網頁 怎么使用 github.io 搭建一個簡單的網頁?】

這里是一張展示 GitHub Pages 靜態網站架構與部署流程的示意圖&#xff0c;可以幫助你更直觀理解整個流程。 要使用 github.io&#xff08;GitHub Pages&#xff09;搭建一個簡單的網頁&#xff0c;你可以按照以下步驟操作&#xff1a; 快速入門&#xff1a;個人網站&#xff…

記錄一次ubuntu20.04 解決gmock not found問題的過程

在電腦上源碼編譯moveit&#xff0c;系統是ubuntu20.04&#xff0c;有三個電腦&#xff0c;分別叫做A,B,C好了&#xff0c;A和C都可以很順暢地走流程編譯通過&#xff0c;但是B遇到了gmock not found的問題&#xff0c;一開始沒當回事&#xff0c;感覺重裝下庫&#xff0c;或者…

Java基礎編程核心案例:從邏輯到應用

Java編程的核心在于將邏輯思維轉化為可執行的代碼。本專欄通過8個實用案例&#xff0c;覆蓋條件判斷、循環結構、數組操作、用戶交互等基礎知識點&#xff0c;展示如何用Java解決實際問題&#xff0c;從簡單游戲到數據計算&#xff0c;逐步構建編程思維。 案例一&#xff1a;剪…

Starlink衛星終端對星策略是終端自主執行的還是網管中心調度的?

以下文章首先來源于Google Gemini的Deep Research的內容,在Deep Research的報告參考了SpaceX公開信息、FCC技術報告、相關專利(如US9906292B2)以及學術研究的綜合分析,并參考了RFWirelessWorld和APNIC博客等二次來源。 文章完成之后,前后發給了Grok和deepseek,讓Grok和d…

【CDA案例】數據分析案例拆解:解鎖數據分析全流程!

在當今數字化時代&#xff0c;數據如同一座座金礦&#xff0c;蘊含著巨大的價值。企業、組織乃至個人都渴望從海量的數據中挖掘出有用的信息&#xff0c;以指導決策、優化運營、提升競爭力。今天我們以一個實際的數據分析案例為藍本&#xff0c;深入拆解其全過程&#xff0c;帶…

vulnhub-drippingblues靶場攻略

1.打開靶場&#xff0c;我們將網絡連接方式改為NAT模式2.然后使用nmap掃描一下nat的網段3.存在21&#xff0c;22&#xff0c;80端口我們先來看一下21端口的ftp協議&#xff0c;發現可以直接匿名登錄&#xff0c;并且可以下載存在的東西4.但是這個壓縮包被加密了&#xff0c;我們…

afsim2.9_使用QtCreator和VSCode編譯

使用QtCreator和VSCode編譯AFSIM2.9源代碼指南 準備工作 在開始編譯AFSIM2.9源代碼前&#xff0c;需要確保您的開發環境滿足以下條件&#xff1a; 安裝QtCreator安裝Visual Studio Code&#xff08;最新穩定版&#xff09;獲取AFSIM2.9源代碼包安裝必要的編譯工具鏈&#xf…

TC39x STM(System Timer)學習記錄

STM有哪些特性&#xff1f;自由運行的 64 位計數器所有 64 位可同步讀取可同步讀取 64 位計數器的不同 32 位部分基于與 STM 部分內容的比較匹配&#xff0c;靈活地產生服務請求在應用復位后自動開始計數若 ARSTDIS.STMxDIS 位清零&#xff0c;應用復位將復位 STM 寄存器&#…

css初學者第四天

<1>snipaste工具的使用snipaste是一個簡單但強大的截圖工具&#xff0c;也可以讓你將截圖貼回屏幕上。常用的快捷方式&#xff1a;1、F1可以截圖&#xff0c;同時測量大小&#xff0c;設置箭頭 書寫文字等2、F3在桌面置頂顯示3、點擊圖片&#xff0c;alt可以取色&#xf…

CompletableFuture實現Excel 多個sheet頁批量導出

CompletableFuture實現Excel 多個sheet頁批量導出 文章目錄 CompletableFuture實現Excel 多個sheet頁批量導出 為什么不能直接合并文件或Sheet? 我的方案合理性 1. 操作實現步驟 1.1、導入所需要的依賴 1.2 、Excel 導入導出對象 1.3、異步生成 Excel 文件到指定路徑 1.4、合并…