首页 > 其他分享 >联合体union详解

联合体union详解

时间:2024-07-18 13:30:11浏览次数:16  
标签:字节 union 成员 联合体 int 详解 内存 data

前言

       本章我们来了解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:适用于节省内存空间,尤其是在需要存储多个可能类型但一次只使用一种类型的数据时。常用于网络协议解析、硬件寄存器访问等场景。

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

标签:字节,union,成员,联合体,int,详解,内存,data
From: https://blog.csdn.net/m0_67669662/article/details/140519529

相关文章

  • nginx出现499错误码的原因以及proxy_ignore_client_abort配置 及 nginx日志配置变量大
    一、nginx出现499错误码的原因以及proxy_ignore_client_abort配置1. nginx出现499错误码的原因    最近发现服务器上出现很多499的错误,出现499错误的原因是客户端关闭了连接,在我这篇文章:服务端在执行时中途关闭浏览器退出之后php还会继续执行吗?个人实践实验得到结果( h......
  • 运维锅总详解Kubernetes之Service
    本文尝试从Service暴露服务方式、Service控制器实现原理、使用规范等方面对Kubernetes中的Service进行详细介绍。一、Kubernetes中的pod有哪些暴露服务的方式各种Kubernetes中暴露服务的方式都有其独特的优缺点,根据具体的使用场景和需求,选择合适的方式非常重要。下面是......
  • TCP协议详解
    传输控制协议(TCP,TransmissionControlProtocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。1.TCP头部格式源/目的端口:表示数据从哪个进程发送,然后发送到哪个进程去32位序列号:发送的数据按照一个字节一个编号存放进去32位确认号:用于给与对方响应,值为收到的TC......
  • 机器学习:详解迁移学习(Transfer learning)
    详解迁移学习深度学习中,最强大的理念之一就是,有的时候神经网络可以从一个任务中习得知识,并将这些知识应用到另一个独立的任务中。所以例如,也许已经训练好一个神经网络,能够识别像猫这样的对象,然后使用那些知识,或者部分习得的知识去帮助您更好地阅读x射线扫描图,这就是所谓的迁移学......
  • 【QT开发】串口通信管理QSerialPort类详解及实战应用
    QSerialPort是Qt提供的一个功能强大、简单易用的串口通信类。通过本文的学习,您应该对QSerialPort的基本使用、高级应用技巧及相关注意事项有了全面的理解。在实际项目中,QSerialPort可以帮助实现与外部设备的串口通信,确保数据的可靠传输和接收。希望本文能帮助您更好地......
  • Java SPI 机制详解
    目录SPI介绍何谓SPI?SPI和API有什么区别?实战演示ServiceProviderInterfaceServiceProvider效果展示ServiceLoaderServiceLoader具体实现自己实现一个ServiceLoader总结:面向对象设计鼓励模块间基于接口而非具体实现编程,以降低模块间的耦合,遵循依赖倒置原则,并......
  • 膜片钳的基本概念—电压钳原理详解
    什么是电压钳  在膜片钳技术出现之前,其实就存在电压钳技术,他的原理是通过向细胞内注射变化的电流,抵消离子通道开放时所产生的离子流,从而将细胞膜电位固定在某一数值,即钳制电压,记录电流。通俗点就是,将细胞上的电压保持为一个我们设定的电压值,同时记录跨膜电流。  作用主要是......
  • docker ps 命令详解
    dockerps命令:-a,–all展现出来所有状态的容器Showallcontainers(defaultshowsjustrunning)-f,–filter过滤显示Filteroutputbasedonconditionsprovided–format格式化显示Pretty-printcontainersusingaGotemplate-n,–list简单理解,就是显......
  • Task2:从baseline代码详解入门深度学习
    Task2:从baseline代码详解入门深度学习准备工作数据集数据集被划分为三种,分别是:训练集,开发集测试集。训练集数量最多,用于训练模型,开发集用于在训练中不断调整模型的参数,架构,测试集用于测试模型模型基于seq2seq模型主要由encoderdecoder两部分构成使用GRU模型大致可以理......
  • Clarke-Wright节约算法详解与Python代码示例
    Clarke-Wright节约算法详解与Python代码示例一、算法详解Clarke-Wright节约算法(简称C-W算法),也称为节约里程法或节约算法,是由Clarke和Wright于1964年提出的一种启发式算法。该算法主要用于解决车辆路径问题(VehicleRoutingProblem,VRP),特别是在运输车辆数目不确定的情况下......