首页 > 编程笔记 > C语言笔记(精华版)

C语言联合体union的用法(非常详细,附带示例)

联合体(union)是C语言中一种特殊的数据类型,它允许在同一内存位置存储不同类型的数据,从而节省内存空间。联合体的所有成员共享同一块内存空间,这意味着在任何给定时刻,联合体只能包含一个成员的值。


联合体的大小由其最大成员的大小决定,这确保了足够的空间来存储任何可能的成员。

联合体的定义

联合体的定义语法与结构体类似,但使用 union 关键字代替 struct,以下是联合体的定义语法:

union 联合体名称 {
    数据类型1 成员1;
    数据类型2 成员2;
    ...
    数据类型n 成员n;
};

在这个语法中,union是关键字,用于声明一个联合体。联合体名称是我们自定义的类型名称,符合C语言标识符命名规则。大括号内列出了联合体的所有成员,每个成员都有自己的数据类型和名称。

注意,定义联合体是一个完整的语法,最后的分号;不能省略。

例如,我们可以定义一个名为 Data 的联合体,它包含整型、浮点型和字符型成员:

union Data {
    int i;
    float f;
    char str[20];
};

在这个例子中,Data 联合体可以存储一个整数、一个浮点数或一个最多包含 20 个字符的字符串。其中,str 是最大的成员,它占用 20 个字节,所以联合体 Data 也占用 20 个字节。

联合体变量的定义

有了联合体类型,就可以声明联合体变量了;这和定义普通变量没有什么区别,只是需要加上 union 关键字。我们可以在定义联合体的同时直接声明变量,也可以先定义联合体类型然后再声明变量。


以下是几种声明和初始化联合体变量的方法:

// 方法 1:定义联合体类型并同时声明变量
union Data {
    int i;
    float f;
    char str[20];
} data;

// 方法 2:使用已定义的联合体类型声明变量
union Data data1, data2;

// 方法 3:声明并初始化联合体变量
union Data data3 = {42};  // 初始化第一个成员 (int i)

// 方法 4:使用指定初始化器
union Data data4 = {.f = 3.14};  // 初始化 float 成员

在初始化联合体变量时,我们只能初始化第一个成员,或者使用指定初始化器来初始化特定的成员。如果不进行显式初始化,联合体变量的内容将是未定义的。

联合体成员的访问

访问联合体的成员与访问结构体的成员非常相似,我们可以使用点号运算符.和箭头运算符->来实现。通过联合体变量访问成员时使用点号,通过联合体指针访问成员时使用箭头。

 

这两种运算符的语法格式如下:

union_variable.member        // 使用点号运算符
union_pointer->member        // 使用箭头运算符

让我们通过一个详细的示例来深入理解这两种访问联合体成员的方式。

#include <stdio.h>

union Data {
    int i;
    float f;
    char str[20];
};

int main() {
    union Data data;
    union Data *ptr = &data;

    // 使用点号运算符访问成员
    data.i = 10;
    printf("整数值: %d\n", data.i);

    data.f = 220.5;
    printf("浮点数值: %.1f\n", data.f);

    strcpy(data.str, "C Programming");
    printf("字符串值: %s\n", data.str);

    // 使用箭头运算符通过指针访问成员
    ptr->i = 20;
    printf("通过指针访问的整数值: %d\n", ptr->i);

    ptr->f = 331.7;
    printf("通过指针访问的浮点数值: %.1f\n", ptr->f);

    strcpy(ptr->str, "Union Example");
    printf("通过指针访问的字符串值: %s\n", ptr->str);

    return 0;
}

通过点号运算符,我们直接访问 data 变量的成员。例如,data.i = 10 将整数值 10 赋给联合体的整数成员。同样,我们可以使用 data.f 和 data.str 来访问浮点数和字符串成员。
 

使用箭头运算符,我们通过指针 ptr 访问联合体的成员。ptr->i = 20 将整数值 20 赋给联合体的整数成员。类似地,我们可以使用 ptr->f 和 ptr->str 来访问浮点数和字符串成员。

需要注意的是,由于联合体的所有成员共享同一块内存,每次我们修改一个成员的值时,其他成员的值也会受到影响。这就是为什么在上面的例子中,我们每次修改一个成员后都立即打印其值。

运行这段代码,我们将得到如下输出:

整数值: 10
浮点数值: 220.5
字符串值: C Programming
通过指针访问的整数值: 20
通过指针访问的浮点数值: 331.7
通过指针访问的字符串值: Union Example

联合体的内存布局

联合体的所有成员共享同一块内存空间,这意味着,在任何时刻只有一个成员包含有效的值。
 

联合体的内存布局遵循以下原则:联合体的大小等于其最大成员的大小,所有成员的起始地址相同。这种设计确保了无论哪个成员被访问,都能正确地读取或写入数据。


当我们修改联合体的一个成员时,其他成员的值也会随之改变,因为它们实际上占用相同的内存位置。

 

在前面的例子中,我们定义了一个名为 Data 的联合体,它包含三个成员:一个整型(int)、一个浮点型(float)和一个字符数组(char[20])。假设在我们的系统中,int 占用 4 字节,float 占用 4 字节,char 占用 1 字节。那么这个联合体的总大小将是 20 字节,这是因为字符数组 str 是最大的成员。

联合体 Data 的内存布局如下所示:

  Data
+-----+  ---------+
|  4  |   i f     |
+-----+  -----    |
|  8  |           |
+-----+           |
|  12 |          str
+-----+           |
|  16 |           |
+-----+           |
|  20 |           |
+-----+  ---------+

每个小方格占用 4 个字节,整个联合体占用 20 个字节。其中,成员 i 和 f 只占用前面 4 个字节,并且它们的内存空间是重复的;成员 str 占用整个联合体的内存空间,因为它是最大的成员。

总结

联合体在以下场景中特别有用:

总之,C语言中的联合体是一种比较特殊的数据类型,它允许在同一内存位置存储不同类型的数据。使用联合体时需要格外小心,因为不当的使用可能导致数据混淆或错误。

相关文章