Bootstrap

联合体union详解

前言

       本章我们来了解C语言中的联合体,它的基本基本使用,内存计算,大小端判断应用与结构体struct的区别等知识点。

什么是联合体

union(联合体)是C语言(及其衍生语言如C++)中一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。union的主要特点是其所有成员共享同一段内存空间,这意味着在任何给定时刻,union只存储其成员中的一个值,且该值是最近一次被赋予的值。

基本用法

union Data {  
    int i;  
    char str;  
};  
  
union Data data;

       在这个例子中,Data是一个union类型,它包含了两个成员:一个int、一个字符char。然而,这两个成员并不是同时存在的;相反,它们共享同一段内存空间。因此,如果你给data.i赋值,那么data.str的值将会变得不可预测,因为它现在包含了int类型的数据的字节表示。

一般的存储是分开这样存的;

而联合体是共用内存的;

使用示例

#include <stdio.h>  
  
union Data {  
    int i;  
    float f;  
};  
  
int main() {  
    union Data data;  
  
    // 初始化int成员  
    data.i = 10;  
    printf("As int: %d\n", data.i); // 输出:As int: 10  
  
    // 现在float成员包含了相同的字节,但可能不是有效的float值  
    printf("As float (may be garbage): %f\n", data.f); // 输出可能是垃圾值  
  
    // 初始化float成员  
    data.f = 220.5;  
    printf("As float: %f\n", data.f); // 输出:As float: 220.500000  
  
    // 现在int成员包含了相同的字节,但可能不是有效的int值  
    printf("As int (may be garbage): %d\n", data.i); // 输出可能是垃圾值  
  
    return 0;  
}

你可以看到当union的一个成员被赋值时,其他成员的值将变得不可预测,因为它们共享同一段内存空间。

内存大小计算

那么给这个联合体分配的内存要怎么计算呢

1,union的大小至少是其最大成员的大小。编译器会确保union有足够的空间来存储其最大的成员。

2,如果最大成员的大小不是最大对齐数的整数倍,则需要将联合体的大小对齐到最大对齐数的整数倍。

union MyUnion {  
    char c[5];  
    int i;  
  
};

在大多数编译器中(特别是考虑到默认对齐数),这个联合体的大小和对齐方式会这样计算:

char c[5]:占用5个字节,但由于是数组,对齐数为1

int i:在大多数平台上占用4个字节,并需要按4字节对齐。

        最大成员是char c[5],5个字节。然而,由于int i 只占用4个字节,如果直接以4字节作为联合体的大小,那么它将小于最大成员的大小。因此,编译器会在char数组之后填充3个字节的空白,使得整个联合体的大小达到8字节,以大于最大成员。

大小端判断应用

    union 类型允许在相同的内存位置存储不同的数据类型。这一特性可以用来判断系统是采用大端(Big-Endian)还是小端(Little-Endian)字节序。

          大端字节序指的是数据的高位字节保存在内存的低地址中,而数据的低位字节保存在内存的高地址中;小端字节序则相反,数据的低位字节保存在内存的低地址中,而数据的高位字节保存在内存的高地址中。

下面是一个使用 union 来判断系统字节序(大端或小端)的示例代码:

#include <stdio.h>  
  
union EndianTest {  
    uint32_t i;  
    char c[4];  
};  
  
int main() {  
    union EndianTest test;  
    test.i = 0x01020304; // 初始化一个整数  
  
    // 检查第一个字节(即低地址处的字节)  
    if (test.c[0] == 1) {  
        printf("Little-Endian\n");  
    } else if (test.c[0] == 0) {  
        printf("Big-Endian\n");  
    } else {  
        printf("Unknown\n");  
    }  
  
    return 0;  
}

将整数 0x01020304 赋值给 i 后,我们检查 c[0] 的值。在小端字节序的系统中,0x01(即整数的最低有效字节)会被存储在 c[0] 中,因为 c[0] 对应于最低的内存地址。而在大端字节序的系统中,0x04(即整数的最高有效字节)会被存储在 c[0] 中。

因此,通过检查 c[0] 的值,我们可以判断系统是采用大端还是小端字节序。

与结构体的区别

1. 内存分配

  • structstruct中的每个成员都拥有独立的内存空间。一个struct变量的总长度是其所有成员的长度之和,且通常会根据编译器的内存对齐规则进行适当调整。
  • unionunion中的所有成员共享同一段内存空间。一个union变量的长度等于其最长成员的长度。在任何时候,union中只有一个成员的值是有效的。

2. 成员赋值与访问

  • struct:对struct中的不同成员赋值不会影响到其他成员的值,因为它们的内存空间是分开的。可以通过成员名来访问struct中的每个成员。
  • union:对union中的某个成员赋值会覆盖其他成员的值,因为它们共享同一段内存。通常只初始化一个成员,并通过相同的成员名来访问当前有效的成员。

3. 使用场景

  • struct:常用于定义复杂的数据结构,如链表节点、学生信息记录等,便于组织和管理数据。每个成员都有独立的存储空间,互不干扰。
  • union:适用于节省内存空间,尤其是在需要存储多个可能类型但一次只使用一种类型的数据时。常用于网络协议解析、硬件寄存器访问等场景。

以上就是所有内容啦,如果觉得有用请来个三连支持一下吧~谢谢~ 

;