C语言中,共用体(Union) 是一种特殊的用户自定义数据类型,它与结构体(struct)相似,但有着不同的内存分配方式。共用体中的所有成员共享同一段内存,因此在任何时候只能存储一个成员的值。结构体(Struct)是一种构造类型或复杂类型,它可以包含多个类型不同的成员。

1、定义声明

共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。共用体有时也被称为联合或者联合体。其定义格式为:

union 共用体名{
成员列表
};

例如,

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

1)共用体也是一种自定义类型,可以通过它来创建变量

例如,

union data{
    int n;
    char ch;
    double f;
};
union data a, b, c;

2)定义共用体的同时创建变量

union data{
    int n;
    char ch;
    double f;
} a, b, c;

3)如果不再定义新的变量,也可以将共用体的名字省略

union{
    int n;
    char ch;
    double f;
} a, b, c;

例如,

#include <stdio.h>
union data{
    int n;
    char ch;
    short m;
};
int main(){
    union data a;
    printf("%d, %d\n", sizeof(a), sizeof(union data) );
    a.n = 0x40;
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
    a.ch = '9';
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
    a.m = 0x2059;
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
    a.n = 0x3E25AD54;
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
    return 0;
}

2、访问共用体成员

访问共用体的成员,需要使用成员访问运算符(.)。

例如,

#include <stdio.h>
#include <string.h>
union Data
{
   int i;
   float f;
   char  str[20];
};
int main( )
{
   union Data data;        
   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C 语言");
   printf( "data.i : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", data.str);
   return 0;
}

上面示例的输出结果中,共用体的 i 和 f 成员的值有损坏,因为最后赋给变量的值占用了内存位置,这也是 str 成员能够完好输出的原因。

共用体是任何时候只能有一个成员带有值。同一时间应该只用一个成员。

例如,

#include <stdio.h>
#include <string.h>
union Data
{
   int i;
   float f;
   char  str[20];
};
int main( )
{
   union Data data;        
   data.i = 10;
   printf( "data.i : %d\n", data.i);
   data.f = 220.5;
   printf( "data.f : %f\n", data.f);
   strcpy( data.str, "C 语言");
   printf( "data.str : %s\n", data.str);
   return 0;
}

3、共用体的内存分配

共用体的所有成员共享同一块内存,共用体的大小是它所有成员中最大成员的大小

#include <stdio.h>

union Data {
    int i;
    float f;
    char c;
};

int main() {
    printf("Size of union Data: %lu bytes\n", sizeof(union Data));
    return 0;
}

4、共用体的使用场景

当一个变量在不同时间需要存储不同类型的数据时,共用体可以节省内存。

在嵌入式编程中,共用体常用于将一段二进制数据解释为不同的数据类型。

在硬件寄存器编程中,可以通过共用体以不同的格式访问同一寄存器。

1)节省内存的共用体

存储一个学生的标识,可能是学生的学号(整数)、图书馆卡号(字符串)或成绩(浮点数),但在任何时间只有其中一种。

#include <stdio.h>

// 定义一个共用体
union StudentInfo {
    int id;
    float grade;
    char libraryCard[20];
};

int main() {
    union StudentInfo student;

    student.id = 12345;
    printf("Student ID: %d\n", student.id);

    student.grade = 87.5;
    printf("Student Grade: %.2f\n", student.grade);

    // 复制字符串到共用体的字符数组中
    snprintf(student.libraryCard, 
    sizeof(student.libraryCard), "LIB2023ABC");
    printf("Library Card: %s\n", student.libraryCard);

    return 0;
}

2)共用体在硬件寄存器编程中的应用

在嵌入式系统中,往往需要直接访问硬件寄存器中的特定位,可以使用共用体来达到这一目的。

#include <stdio.h>

// 定义一个共用体,用于访问32位寄存器的不同位段
union Register {
    unsigned int reg;
    struct {
        unsigned int lowByte : 8;  // 低8位
        unsigned int midByte : 8;  // 中间8位
        unsigned int highByte : 8; // 高8位
        unsigned int control : 8;  // 控制位
    };
};

int main() {
    union Register reg;

    // 直接访问整个寄存器
    reg.reg = 0x12345678;
    printf("Register value: 0x%X\n", reg.reg);
    printf("Low Byte: 0x%X\n", reg.lowByte);
    printf("Mid Byte: 0x%X\n", reg.midByte);
    printf("High Byte: 0x%X\n", reg.highByte);
    printf("Control: 0x%X\n", reg.control);

    return 0;
}

注意:

由于共用体的所有成员共享同一段内存,赋值一个成员会覆盖其他成员的值。

如果在共用体中同时访问多个成员,结果是未定义的,因为你无法预期其他成员会有什么值。

在一些内存受限的场合,如嵌入式系统,共用体可以显著减少内存使用量。

推荐文档