【在主画面加入捷径】
       
【选择语系】
繁中 简中

[C 语言] 程序设计教学:如何使用联合 (Union)

【赞助商连结】

    联合 (union) 乍看和结构 (structure) 有点像,但联合内的属性共用同一块内存,故同一时间内仅能用联合内其中一种属性。联合主要用来表示同概念但不同数据类型的实例。

    声明联合

    使用 union 保留字可声明联合,如下例:

    union sample {
        float f;
        int i;
        char ch;
    };
    
    int main(void) {
        union sample s;
        
        s.i = 3;
        
        return 0;
    }
    

    我们可以用 typedef 来简化联合的类型名称:

    // Forward declaration.
    typedef union sample Sample;
    
    union sample {
        float f;
        int i;
        char ch;
    };
    
    int main(void) {
        Sample s;
        
        s.f = 3.0;
        
        return 0;
    }
    

    如果想节省命名空间的符号量,可改用以下方法来声明:

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

    存取联合中的元素

    我们先前提过,联合在同一时间同仅能储存其中一个属性,故以下程序会引发错误:

    #include <assert.h>
    
    typedef union sample Sample;
    
    union sample {
        float f;
        int i;
        char ch;
    };
    
    int main(void) {
        Sample 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 Amount;
    
    union amount {
        unsigned unit;
        float liter;
    };
    
    typedef struct item Item;
    
    struct item {
        char *name;
        unsigned short amountType;
        Amount howmuch;
    };
    
    int main(void) {
        Item books = {
            .name = "C Programming Tutorial",
            .amountType = 1,
            .howmuch.unit = 4
        };
        
        Item apples = {
            .name = "Apple",
            .amountType = 1,
            .howmuch.unit = 6
        };
        
        Item juices = {
            .name = "Orange Juice",
            .amountType = 2,
            .howmuch.liter = 3.2
        };
        
        Item 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"); // tailing newline.
        }
        
        return 0;
    }
    

    内嵌在联合内的结构

    除了联合可嵌在结构内,结构也可以嵌在联合内。不过,我们为了记录联合所用的类型,外部会再用一层结构包住该联合,就会形成三层的复合类型,如下例:

    #include <stddef.h>
    #include <stdio.h>
    
    typedef struct _rgb RGB;
    
    struct _rgb {
        unsigned short r;
        unsigned short g;
        unsigned short b;
    };
    
    typedef union _color_t {
        char *description;
        RGB rgb;
    } color_t;
    
    typedef struct color Color;
    
    struct color {
        unsigned short type;
        
        color_t data;
    };
    
    int main(void) {
        Color red = {
            .type = 1,
            .data.description = "red"
        };
        
        Color orange = {
            .type = 1,
            .data.description = "orange"
        };
        
        Color beige = {
            .type = 2,
            .data.rgb = { 245, 245, 220 }
        };
        
        Color 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;
    }
    
    【赞助商连结】