首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C 語言聯合體詳解:定義、記憶體佈局、巢狀結構與實戰範例

     編輯:關於C

聯合體 vs 結構體:核心差異

特性結構體聯合體
記憶體分配各成員各自擁有空間,總大小 = 成員大小之和(含對齊填充)所有成員共享同一塊記憶體,大尺寸 = 最大成員大小(對齊後)
同時存在性所有成員同時存在同一時刻僅能持有一個成員的值
賦值行為可同時對多成員賦值新賦值會覆蓋舊值
初始化可初始化多成員C 標準僅允許初始化第一個成員(C99 指定初始化器可指定任一)

聯合體定義語法

union 聯合體名 {
    成員型別 成員名;
    ...
};

範例:教師/學生通用資料

union PerData {
    int class;        // 學生:班級編號
    char office[10];  // 教師:教研室名稱
};

聯合體變數宣告(三種形式)

// 1. 先定義後宣告
union PerData { int class; char office[10]; };
union PerData a, b;

// 2. 定義同時宣告
union PerData {
    int class;
    char office[10];
} a, b;

// 3. 匿名聯合體直接宣告
union {
    int class;
    char office[10];
} a, b;

記憶體佈局圖解

union PerData { int class; char office[10]; };  // 假設 int 4 bytes

變數 a:
+------------------+
| office[0..9]     |  10 bytes (最大成員)
+------------------+
| class (前 4 bytes 重疊) |
+------------------+

sizeof(union PerData) = 10  (對齊後可能為 12)
- 賦值 a.class = 5 時,僅使用前 4 bytes
- 賦值 strcpy(a.office, "CSIE") 時,使用全部 10 bytes

存取成員

union PerData data;
data.class = 3;           // 整數賦值
data.office[0] = 'A';     // 字元陣列賦值(覆蓋 class)

// 透過指標存取
union PerData *p = &data;
p->class = 4;
strcpy(p->office, "Math");

注意:聯合體變數本身不可直接賦值或比較,必須透過具體成員。

巢狀結構:結構體內嵌聯合體

完整範例:人員資料表

#include <stdio.h>
#include <string.h>

struct Person {
    char name[10];
    int age;
    char job;              // 's' = 學生, 't' = 教師
    union {
        int class;
        char office[10];
    } dept;
};

int main(void)
{
    struct Person list[2];

    for (int i = 0; i < 2; i++) {
        printf("輸入姓名 年齡 職業(s/t) 部門: ");
        scanf("%9s %d %c", list[i].name, &list[i].age, &list[i].job);
        if (list[i].job == 's')
            scanf("%d", &list[i].dept.class);
        else
            scanf("%9s", list[i].dept.office);
    }

    printf("%-10s %3s %3s %s\n", "Name", "Age", "Job", "Dept");
    for (int i = 0; i < 2; i++) {
        if (list[i].job == 's')
            printf("%-10s %3d %3c %d\n",
                   list[i].name, list[i].age, list[i].job, list[i].dept.class);
        else
            printf("%-10s %3d %3c %s\n",
                   list[i].name, list[i].age, list[i].job, list[i].dept.office);
    }
    return 0;
}

關鍵點

  • dept 是匿名聯合體成員,直接以 list[i].dept.class 存取。
  • scanf 讀取陣列成員(name、office)時不加 &,因陣列名已退化為指標。
  • 透過 job 欄位判別當前使用哪個聯合體成員(標籤欄位模式)。

聯合體陣列與指標

  • 可宣告聯合體陣列:union PerData arr[100];
  • 可使用指向聯合體的指標:union PerData *p = &data;
  • 限制:C 標準規定聯合體不可作為函式參數傳遞,也不可作為函式回傳值(但可傳遞指標或包含聯合體的結構體)。

實際應用場景

  1. 型別安全的異質資料容器:配合標籤欄位實現類似 variant 的效果。
  2. 硬體暫存器映射:同一記憶體位址以不同位欄位解讀。
  3. 網路協定封包:同一緩衝區依協定版本解析為不同結構。
  4. 省記憶體:互斥欄位共享空間(如嵌入式系統)。

總結

  • 聯合體讓多種型別共用同一記憶體區塊,大小取決於最大成員。
  • 核心用法:標籤欄位 + 聯合體,運行時根據標籤決定如何解讀資料。
  • 巢狀於結構體中可構建靈活的異質資料結構。
  • 嚴禁同時依賴多個成員的值——行為未定義。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved