開源技術教學文件網 如何使用聯合 (Union)

最後修改日期為 AUG 21, 2018

前言

聯合 (union) 乍看和結構 (structure) 有點像,但聯合內的屬性共用同一塊記憶體,故同一時間內僅能用聯合內其中一種屬性。聯合主要用來表示同概念但不同資料類型的實體。

宣告聯合

使用 union 保留字可宣告聯合,如下例:

union sample_t {
    float f;
    int i;
    char ch;
};

int main(void)
{
    union sample_t s;
    
    s.i = 3;
    
    return 0;
}

我們可以用 typedef 來簡化聯合的型別名稱:

/* Forward declaration. */
typedef union sample_t sample_t;

union sample_t {
    float f;
    int i;
    char ch;
};

int main(void)
{
    sample_t s;
    
    s.f = 3.0;
    
    return 0;
}

如果想節省命名空間的符號量,可改用以下方法來宣告:

typedef union {
    float f;
    int i;
    char ch;
} sample_t;

這時候的聯合是匿名聯合 (anonymous union),故不占用命名空間。

存取聯合中的元素

我們先前提過,聯合在同一時間同僅能儲存其中一個屬性,故以下程式會引發錯誤:

#include <assert.h>

typedef union sample_t sample_t;

union sample_t {
    float f;
    int i;
    char ch;
};

int main(void)
{
    sample_t s;
    
    s.i = 3;
    
    assert(s.i == 3);
    
    // Update s.
    s.f = 5.0;
    
    assert(s.f == 5.0);

    // Error!
    assert(s.i == 3);
    
    return 0;
}

內嵌在結構內的聯合

聯合和結構相似,都是一種複合型別,我們可以在結構內嵌入聯合,這時候的好處在於我們可以用一個額外的欄位來記錄目前聯合中使用的型別,如以下實例:

#include <stddef.h>
#include <stdio.h>

typedef union amount_t amount_t;

union amount_t {
    unsigned unit;
    float liter;
};

typedef struct item_t item_t;

struct item_t {
    char *name;
    unsigned short amountType;
    amount_t howmuch;
};

int main(void)
{
    item_t books = {
        .name = "C Programming Tutorial",
        .amountType = 1,
        .howmuch.unit = 4
    };
    
    item_t apples = {
        .name = "Apple",
        .amountType = 1,
        .howmuch.unit = 6
    };

    item_t juices = {
        .name = "Orange Juice",
        .amountType = 2,
        .howmuch.liter = 3.2
    };
    
    item_t items[] = {books, apples, juices};
    
    for (size_t i = 0; i < 3; i++) {
        printf("%s: ", items[i].name);
        
        if (items[i].amountType == 1) {
            printf("%d units", items[i].howmuch.unit);
        } else {
            printf("%.2f liters", items[i].howmuch.liter);
        }
        
        printf("\n"); /* trailing newline. */
    }
    
    return 0;
}

內嵌在聯合內的結構

除了聯合可嵌在結構內,結構也可以嵌在聯合內。不過,我們為了記錄聯合所用的型別,外部會再用一層結構包住該聯合,就會形成三層的複合型別,如下例:

#include <stddef.h>
#include <stdio.h>

typedef struct rgb_t rgb_t;

struct rgb_t {
    unsigned short r;
    unsigned short g;
    unsigned short b;
};

typedef union color_data_t color_data_t;

union color_data_t {
    char *description;
    rgb_t rgb;
};

typedef struct color_t color_t;

struct color_t {
    unsigned short type;    
    color_data_t data;
};

int main(void)
{
    color_t red = {
        .type = 1,
        .data.description = "red"
    };

    color_t orange = {
        .type = 1,
        .data.description = "orange"
    };

    color_t beige = {
        .type = 2,
        .data.rgb = { 245, 245, 220 }
    };

    color_t colors[] = { red, orange, beige };

    for (size_t i = 0; i < 3; i++) {
        if (colors[i].type == 1) {
            printf("%s\n", colors[i].data.description);
        } else {
            printf("(%u, %u, %u)\n", 
                colors[i].data.rgb.r,
                colors[i].data.rgb.g,
                colors[i].data.rgb.b);
        }
    }

    return 0;
}

電子書籍

如果你覺得這篇 C 語言的技術文章對你有幫助,可以看看以下完整的 C 語言程式設計電子書:

現代 C 語言程式設計

分享本文
Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Yahoo
追蹤本站
Facebook Facebook Twitter