C和指针 第10章 结构和联合 10.6 联合

10.6 联合
    和结构相比,联合(union)可以说是另一种“动物”了。联合的声明和结构类似,但它的行为方式却和结构不同。联合的所有成员引用的是内存中的相同位置。如果想在不同的时刻把不同的东西存储于同一个位置,就可以使用联合。
    首先,如下例所示:
    union {
        float f;
        int i;
    } fi;
    在一个浮点数和整型都是32位的机器上,变量fi只占据内存中一个32位的字。如果成员f被使用,这个字就作为浮点值访问;如果成员i被使用,这个字就作为整型值访问。所以,下面这段代码
    fi.f = 3.14159;
    printf( "%d\n", fi.i );
    首先把π的浮点数表示形式存储于fi,然后把这些相同位当做一个整型值打印输出。注意,这两个成员所引用的位相同,仅有的区别在于每个成员的类型决定了这些位如何解释。
    为什么人们有时想使用类似此例的形式呢?如果你想看看浮点数是如何存储在一种特定的机器中,但又对其他内容不感兴趣,联合就可能有所帮助。这里有一个更为现实的例子。BASIC解释器的任务之一就是记住程序所使用的的变量的值。BASIC提供了几种不同类型的变量,所以每个变量的类型必须和它的值一起存储。下面这个结构用于保存这个信息,但它的效率不高。
    struct VARIABLE {
        enum { INT, FLOAT, STRING } type;
        int int_value;
        float float_value;
        char *string_value;
    }; 
    当BASIC程序中的一个变量被创建时,解释器就创建一个这样的结构并记录变量的类型。然后,根据变量的类型,把变量的值存储在这3个值字段的其中一个。
    这个结构的低效之处在于它所占用的内存---每个VARIABLE结构存在两个未使用的值字段。联合就可以减少这种浪费,它把这3个值字段的每一个都存储于同一个内存位置。这3个字段并不会冲突,因为每个变量只可能具有一种类型,这样在某一时刻,联合的这几个字段只有一个被使用。
    struct VARIABLE {
        enum { INT, FLOAT, STRING } type;
        union {
            int i;
            float f;
            char *s;
        } value;
    }; 
    现在,对于整型变量,你将把type字段位置设置为INT,并把整型值存储于value.i字段。对于浮点值,你将使用value.f字段。当以后得到这个变量的值时,对type字段进行检查可以决定使用哪个值字段。这个选择决定内存位置如何被访问,所以同一个位置可以用于存储这3种不同类型的值。注意,编译器并不对type字段进行检查,以证实程序使用的是正确的联合成员。维护并检查type字段是程序员的责任。如果联合的各个成员具有不同的长度,联合的长度就是它最长成员的长度。
    10.6.1 变体记录(variant record)
    从概念上说,这就是我们刚刚讨论过的那个情况---内存中某个特定的区域将在不同的时刻存储不同类型的值。但是,在现在这个情况下,这些值比简单的整型或浮点型更为复杂,它们的每一个都是完整的结构。
    下面这里例子取自一个存货系统,它记录了两种不同的实体:零件(part)和装配件(subassembly)。零件就是一种小配件,从其他生产厂家购得。它具有不同的属性,如购买来源,购买价格等。装配件是我们制造的东西,它由一些零件及其装配件组成。
    下面两个结构指定每个零件和装配件的内容。
    struct PARTINFO {
        int cost;
        int supplier;
        ...
    }; 
    struct SUBASSYINFO {
        int n_parts;
        struct {
            char partno[10];
            short quan;
        } parts[MAXPARTS];
    };
    接下来的存货(inventory)记录包含了每个项目的一般信息,并包括了一个联合:或者用于存储零件信息,或者用于存储装配件信息。
    struct INVREC {
        char partno[10];
        int quan;
        enum { PART, SUBASSY } type;
        union {
            struct PARTINFO part;
            struct SUBASSYINFO subassy;
        } info;
    }; 
    这里有一些语句,用于操作名叫rec的INVREC结构变量
    if( rec.type == PART ){
        y = rec.info.cost;
        z = rec.info.part.supplier;
    }else{
        y = rec.info.subassy.nparts;
        z = rec.info.subassy.parts[0].quan;
    }
    尽管并非真实,但这段代码说明了如何访问联合的每个成员。
    在一个成员长度不同的联合里,分配给联合的内存数量取决于它的最长成员的长度。这样,联合的长度总是足以容纳它最大的成员。如果这些成员的长度相差悬殊,当存储长度较短的成员时,浪费的空间是相当客观的。在这种情况下,更好的方法是在联合中存储指向不同成员的指针而不是直接存储成员本身。所有指针的长度都是相同的,这样就解决了内存浪费的问题。当它决定需要哪个成员时,就分配正确数量的内存来存储它。动态内存分配包含了一个用于说明这种技巧的例子。
    10.6.2 联合的初始化
    联合变量可以被初始化,但这个初始值必须是联合第一个成员的类型,而且它必须位于一对花括号里面。例如,
    union {
        int a;
        float b;
        char c[4];
    }x = { 5 };
    把x.a初始化为5。
    我们不能把这个类量初始化一个浮点值或字符值。如果给出的初始值是其他任何类型,它就会转换(如果可能的话)为一个整型并赋值给x.a。 

基于STM32F407,使用DFS算法实现最短迷宫路径检索,分为三种模式:1.DEBUG模式,2. 训练模式,3. 主程序模式 ,DEBUG模式主要分析bug,测量必要数据,训练模式用于DFS算法训练最短路径,并将最短路径以链表形式存储Flash, 主程序模式从Flash中….zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值