《《《《《正文》》》》》
《结构体的不足》
在C语言中,如果要你描述一辆车的属性,最快最简洁的方法就是构建结构体:
struct car_info{ char *logo; //品牌 long country; //国家 int price; //价格 char type; //类型};
如上定义的结构体就可以很方便的描述一辆车的信息,而且多辆车的话只需新增一个car_info定义的变量而已,方便且简洁明了!
如果后续还增加车的属性的话,只需在结构体中增加一个参数就可以了,如下:
struct car_info{ ... int color; //颜色};
但是有没有想过,新能源车和传统型车之间的属性不同,就是新能源有的参数在传统型车上是没有的,比如电池充电速度、电池容量等属性;同样,传统型车上有的属性是新能源车上没有的,比如用油类型等属性;
那有人说,简单,新能源和传统车型各开一个结构体:
struct NewCar_info{ char *logo; //品牌 long country; //国家 int price; //价格 char type; //类型 int timer;//充电速度 int batery; //电池容量};
struct OldCar_info{ char *logo; //品牌 long country; //国家 int price; //价格 char type; //类型 int oiltype;//用油类型 int Oilspend; //耗油量};
这样子,只要调用定义就可以了,如下:
// 新能源车型struct NewCar_info Ninfo;// 传统车型struct OldCar_info Oinfo;
不过,在程序里讲究封装这个概念,我们往往喜欢把相同的东西封装打包,这样能节省很多空间,而且下次更改也只需更改封装里的东西,不必全代码一个一个的更改,所以干脆就写成一个结构体吧,如下:
struct NOCar_info{ char *logo; //品牌 long country; //国家 int price; //价格 char type; //类型 int timer;//充电速度 int batery; //电池容量 int oiltype;//用油类型 int Oilspend; //耗油量};
如上结构体,依然可以描述新能源车型和传统车型,如下:
// 新能源车型struct NOCar_info Ninfo;// 传统车型struct NOCar_info Oinfo;
上面只要特殊处理一下,新能源不能访问传统属性,传统不能访问新能源的属性就可以了,但是他们之间耦合会增加很多,这样也是行得通的;
但是因为今天是讲union,自然要挑骨头,有人会说,嵌入式本来内存就紧张,上面这种方法浪费内存,听起来无可反驳,那怎么办?
《union大显身手》
union的出现就很好解决了浪费内存和耦合高的问题,我们来看看,它是怎么解决的。
先来看看union的语法:
struct NewCar_info{ int timer;//充电速度 int batery; //电池容量};struct OldCar_info{ int oiltype;//用油类型 int Oilspend; //耗油量};struct NOCar_info{ char *logo; //品牌 long country; //国家 int price; //价格 char type; //类型 union{ struct NewCar_info NCar; struct OldCar_info OCar; };};
我们来看NOCar_info中的union内的参数,意思就是其中的2个struct公用一块内存,什么意思呢?就是你改变 struct NewCar_info NCar中的值,struct OldCar_info OCar也会被同样改变,且是同一个内存同一个值,反过来亦是如此,因此成为共用体、联合体;
如上我们只需一个结构体,就可解决新能源和传统车型自己的属性不同问题;
// 新能源、传统struct NOCar_info NO_Car;
若要访问新能源车型的充电时间和电池容量,可如下操作:
timer = NO_Car.NCar.timer;batery = NO_Car.NCar.batery;
若要访问传统车型的用油类型和油耗量,可如下操作
oiltype = NO_Car.OCar.oiltype;Oilspend = NO_Car.OCar.Oilspend;
这样子就解决了,上面的浪费内存,耦合读高的问题;
union当然也有其他的用处,主要原理是利用公用内存这一个特性;
《我常用union的场景》
串口发送往往是按字节发送,因此一个32位的数据,需要拆分成4个字节,然后依次发送;按往常,我们做位运算可以得出4个字节的数据,但是union就可以直接取出,具体实现伪代码如下:
typedef union{ uint8_t B8[4]; uint16_t B16[2]; uint32_t B32;}B32_B8_TypeDef;
uint32_t Send_Data = 0x12345678;B32_B8_TypeDef Uart_Send;
void main(void){ //数据复制 Uart_Send.B32 = Send_Data; //字节复制 Uart[0]= Uart_Send.B8[0]; Uart[1]= Uart_Send.B8[1]; Uart[2]= Uart_Send.B8[2]; Uart[3]= Uart_Send.B8[3]; //发送数据}
《《《《《END》》》》》