C语言union总结

C语言union总结

最近在工作中看到前辈写了串代码,使用union,加深了对C语言的认识,感叹C语言的博大精深!

需要实现的功能:

从模块有5个按键,每个按键有5种状态。主模块与从模块串口相连。当从模块按下按键时发送按键数据到串口,主模块通过串口接收的数据判断哪个按键触发及按键状态。分别为这5个按键做一个接口,方便别人直接调取来读取按键状态。

以下为设置的按键及状态的标志代码(自己稍加修改),代码1:

#include "stdio.h"

typedef unsigned char uint8_t;

typedef enum    //规定STATE1=0x00 STATE2=0x01 STATE3=0x02 STATE4=0x03 STATE5=0x07
{
    STATE1 = 0,
    STATE2,
    STATE3,
    STATE4,
    reserive1,  //(保留三位)
    reserive2,
    reserive3,
    STATE5
}Key_State_Type;

typedef union   //KEY1-5表示5个按键,每个按键5中状态STATE1-5。
{
    uint8_t _data[2];   //按键5个状态为0x01-0x07,即3个位,5个按键就是5*3=15位,因此2个u8变量即可表示5个按键
    struct
    {
        uint8_t KEY1     :3;    
        uint8_t KEY2     :3;
        uint8_t KEY3     :3;
        uint8_t KEY4     :3;
        uint8_t KEY5     :3;
        uint8_t reserive :1;    //(保留一位)

    }Key_Type;
    
}Key_Value_Type;

int main(){

    Key_Value_Type key;

    key.Key_Type.KEY1 = STATE5;
    printf("KEY1_STATE = %d\n",key.Key_Type.KEY1);

    key.Key_Type.KEY2 = STATE4;
    printf("KEY2_STATE = %d\n",key.Key_Type.KEY2);
    printf("KEY1_STATE = %d\n",key.Key_Type.KEY1);

}

运行结果:
KEY1_STATE = 7
KEY2_STATE = 3
KEY1_STATE = 7

查阅C语言中union的资料了解到:

1. 联合体union的基本特性(和struct的相同与不同)

联合体(union)的声明和结构与结构体类似,但是本质不同。

联合的所有成员引用的是内存中的相同位置。当你想在不同时刻把不同的东西存储于同一位置时,就可以使用联合。

结构体(struct)中所有变量是“共存”的——优点是“有容乃大”,全面;缺点是struct内存空间的分配是粗放的,不管用不用,全分配。

而联合体(union)中是各变量是“互斥”的——缺点就是不够“包容”;但优点是内存使用更为精细灵活,也节省了内存空间。
用一个例子来说明,代码2:

#include "stdio.h"

typedef unsigned char uint8_t;

typedef union
{
    uint8_t union1;
    uint8_t union2;
    uint8_t union3;
    
}Union_Type;

typedef struct
{
    uint8_t struct1;
    uint8_t struct2;
    uint8_t struct3;

}Struct_Type;

main(){

    Union_Type union_type;
    Struct_Type struct_type;

    union_type.union1 = 5;
    printf("union1 = %d\n",union_type.union1);
    printf("union2 = %d\n",union_type.union2);
    printf("union3 = %d\n",union_type.union3);
    printf("************\n");

    union_type.union2 = 8;
    printf("union1 = %d\n",union_type.union1);
    printf("union2 = %d\n",union_type.union2);
    printf("union3 = %d\n",union_type.union3);
    printf("************\n");

    union_type.union3 = 1;
    printf("union1 = %d\n",union_type.union1);
    printf("union2 = %d\n",union_type.union2);
    printf("union3 = %d\n",union_type.union3);
    printf("************------------\n");

    struct_type.struct1 = 5;
    printf("struct1 = %d\n",struct_type.struct1);
    printf("struct2 = %d\n",struct_type.struct2);
    printf("struct3 = %d\n",struct_type.struct3);
    printf("************\n");

    struct_type.struct2 = 8;
    printf("struct1 = %d\n",struct_type.struct1);
    printf("struct2 = %d\n",struct_type.struct2);
    printf("struct3 = %d\n",struct_type.struct3);
    printf("************\n");

    struct_type.struct3 = 1;
    printf("struct1 = %d\n",struct_type.struct1);
    printf("struct2 = %d\n",struct_type.struct2);
    printf("struct3 = %d\n",struct_type.struct3);
    printf("************\n");

}

运行结果:
union1 = 5
union2 = 5
union3 = 5
************
union1 = 8
union2 = 8
union3 = 8
************
union1 = 1
union2 = 1
union3 = 1
************------------
struct1 = 5
struct2 = 0
struct3 = 0
************
struct1 = 5
struct2 = 8
struct3 = 0
************
struct1 = 5
struct2 = 8
struct3 = 1
************

由此可以看出union中共用一个内存的概念了,通过代码1发现union中可以使用struct,这也是一个巧妙的用法。

2.多种访问内存途径共存(双刃剑)

举例,代码3:

#include<stdio.h>

typedef union
{
        long int a;
        int b;
}Union_Typedef;

main(){
        Union_Typedef union_Typedef;
        union_Typedef.a = 5;
        printf("union_Typedef.b is %d\n", union_Typedef.b);
        union_Typedef.b = 6;
        printf("now union_Typedef.a is %ld! the address is %p\n",union_Typedef.a,&union_Typedef.a);
        printf("now union_Typedef.b is %d! the address is %p\n",union_Typedef.b,&union_Typedef.b);
}

运行结果:
union_Typedef.b is 5
now union_Typedef.a is 6! the address is 000000000061FE1C
now union_Typedef.b is 6! the address is 000000000061FE1C

所以说,union完全就是共用一个内存首地址,并且各种变量名都可以同时使用,操作也是共同生效。如此多的access内存手段,确实好用,不过这些“手段”之间却没法互相屏蔽——就好像数组+下标和指针+偏移一样。

上例中改了union_Typedef.a的值,结果union_Typedef.b也能读取,那么也许我还以为union_Typedef.b是我想要的值呢,因为上边提到了union的内存首地址肯定是相同的,那么还有一种情况和上边类似:

一个int数组变量a,一个long int(32位机中,long int占4字节,与int相同)变量b,即使没给int变量b赋值,因为数据类型相同,使用int变量b也完全会拿出int数组a中的a[0]来,这时可能误以为使用的是变量b。

3.联合体union和大小端(big-endian、little-endian):

下边示范了一种用途,代表四个含义的四个变量,但是可以用一个int来操作,直接int赋值,无论内存访问(指针大小的整数倍,访问才有效率),还是时间复杂度(一次和四次的区别,而且这四次有三次都是不整齐的地址),都会低一些。

代码4:

#include<stdio.h>
typedef union
{
        char c[4];
        int i;
}Union_Typedef;
 
int main(){
        Union_Typedef union_Typedef;
        union_Typedef.c[0] = 0x04;//因为是char类型,数字不要太大,算算ascii的范围~
        union_Typedef.c[1] = 0x03;//写成16进制为了方便直接打印内存中的值对比
        union_Typedef.c[2] = 0x02;
        union_Typedef.c[3] = 0x01;
//数组中下标低的,地址也低,按地址从低到高,内存内容依次为:04,03,02,01。总共四字节!
//而把四个字节作为一个整体(不分类型,直接打印十六进制),应该从内存高地址到低地址看,0x01020304,低位04放在低地址上。
        printf("%x\n",union_Typedef.i);
}

运行结果:
1020304

因此我的64位Windows是小端(little-endian)。

4.联合体union所占内存空间大小:

union的首地址是固定的,内存所占大小等于union成员中内存所占最大的变量内存。

代码5:

#include<stdio.h>
typedef union
{
        char c[4];
        int i;
}Union_Typedef;
 
int main(){
        Union_Typedef union_Typedef1;

        printf("The union_Typedef1 size:%d\n",sizeof(union_Typedef1));
}

运行结果:
The union_Typedef1 size:4

由此看出一个union_Typedef1所占内存大小就是int类型变量所占内存大小。

这些只是union的一些基础的用法,但是复杂的用法都是建立在此之上的,union中可以有struct,类似的struct中也可以有union,这些用法在日后使用中若遇到问题再做补充总结。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

studyingdda

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值