前言

联合(union)是一种特殊的数据类型,和结构体很像,结构体各成员变量有自己独立的存储位置,而联合的成员变量共享同一片存储区域,因此联合变量再一个时刻只能保存它的某一个成员的值。

联合的定义和初始化

联合的定义方式与结构体是一样的,只是把关键字 struct 改成 union:

union [标签名称]
{
成员声明列表
};

下面的例子定义了一个名为Data的联合类型,它有 3 个成员:i、x 和 str:

union Data
{
int i;
double x;
char str[16];
};

这种类型的对象可以存储一个整数、一个浮点数或一个短字符串。

下面的声明定义了一个 union Data 类型的对象 var 和一个 unionData 类型的数组 myData,它有 100 个元素(联合的空间大小为它最大成员的空间大小):

union Data var, myData[100];

联合成员值的获取和修改

获取联合成员值的方式和获取结构体成员的方式一样。但是与结构体不同的是,当改变一个联合成员的值时,实际上修改了该联合所有成员的值。

联合的初始化

与结构一样,C99 允许在初始化器中使用成员指示符来指示哪个成员被初始化。而且,如果初始化器没有成员指示符,那么就与联合内的第一个成员关联。具有自动存储类的联合对象也可以使用已有的同类型对象来初始化。下面是一些初始化例子:

union Data var1 = { 77 },
var2 = { .str = "Mary" },
var3 = var1,
myData[100] = { {.x= 0.5}, { 1 }, var2 };

数组 myData 中的元素如果没有指定初始化器,会被隐式地初始化为 0 值。

union的应用:浮点型转换为4字节整型

在串口、IIC、SPI等数据传送时,基本上都是一次传送一个字节的数据,如果我们要传送的是浮点类型的数据呢?常用的方法是将浮点数乘以一个倍数,如10,100,1000,10000等,然后将其转换为整型数据再转化为单个字节进行传送。如果这个数据是要进行显示的话,那么这样做并没有什么不好。但是如果这个数是要传输给另端进行继续计算的话,那么就要考虑另一种方法了,就是直接将浮点数据转换为4个单字节,在另一端接受完数据后再转化为浮点数据,这种方式不会造成精度的丢失,计算量也比较小。

【示例程序】:

#include <stdio.h>

typedef union
{
float fdata; //fdata和ldata共用存储空间
int ldata;
} FloatLongType; //将浮点数f转化为4个字节数据存放在byte[4]中
void Float_to_Byte(float f,unsigned char byte[])
{
FloatLongType fl;
fl.fdata=f;
byte[0]=(unsigned char)fl.ldata;
byte[1]=(unsigned char)(fl.ldata>>8);
byte[2]=(unsigned char)(fl.ldata>>16);
byte[3]=(unsigned char)(fl.ldata>>24);
} //将4个字节数据byte[4]转化为浮点数存放在*f中
void Byte_to_Float(float *f,unsigned char byte[])
{
FloatLongType fl;
fl.ldata=0;
fl.ldata=byte[3];
fl.ldata=(fl.ldata<<8)|byte[2];
fl.ldata=(fl.ldata<<8)|byte[1];
fl.ldata=(fl.ldata<<8)|byte[0];
*f=fl.fdata;
} int main()
{
float f=123456.781234; //要转换的浮点数
unsigned char byte[4]= {0}; //转换后的4个字节数据存放的数组 printf("float data=%f\n",f);
//float 转换为 4个字节数据
Float_to_Byte(f,byte);
//输出转换后的4个字节数据
printf("%f to : %x %x %x %x \n", f, byte[0], byte[1], byte[2], byte[3]);
//把byte的4个字节数据转换为float
Byte_to_Float(&f,byte);
printf("float data=%f\n",f); //输出转换后的结果 return 0;
}

【输出结果】:

float data=123456.781250
123456.781250 to : 64 20 f1 47
float data=123456.781250

可以看出,浮点型数据123456.781250被转换成了64-20-f1-47,4个字节的数据。

不使用联合将单精度浮点型转换成4个字节

在使用单片机和匿名上位机通信,当传输的是一个float类型的数据时,我们需要将float类型数据转换为4个字节的char类型然后通过串口发出去才可以正常显示,

以下是我写的一个函数,不使用联合,可以把一个浮点型数据转换成4个字节的数据,然后通过串口发送出去:

//一个单精度浮点数据的发送
void ANO_SendFloat(int channel, float f_dat)
{
u8 tbuf[8];
int i;
unsigned char *p; for(i = 0; i <= 7; i++)
tbuf[i] = 0; p=(unsigned char *)&f_dat;
tbuf[0] = 0x88;
tbuf[1] = channel; //0xA1
tbuf[2] = 4;
tbuf[3]=(unsigned char)(*(p+3)); //取float类型数据存储在内存中的四个字节
tbuf[4]=(unsigned char)(*(p+2));
tbuf[5]=(unsigned char)(*(p+1));
tbuf[6]=(unsigned char)(*(p+0)); for(i=0; i<=6; i++)
tbuf[7] += tbuf[i]; //校验和
//printf("%s",tbuf); //串口发送字符串
}

参考资料:

历史精选文章:


欢迎大家关注我的个人博客

或微信扫码关注我的公众号

C语言学习之联合类型的更多相关文章

  1. 【C语言学习】存储类型

    C语言中的存储类型主要有四种:auto.static.extern.register ★auto存储类型 默认的存储类型.在C语言中,假设忽略了变量的存储类型,那么编译器就会自己主动默认为auto型 ...

  2. C语言学习之枚举类型

    前言 枚举(enum)类型是计算机编程语言中的一种数据类型.枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把 ...

  3. c语言学习笔记 - 枚举类型

    今天学习了c语言的枚举类型的使用,可能是PHP里没使用过,开始看的时候还是觉得有点怪,后来做了下例子才理解,这里做个笔记记录一下. #include <stdio.h> enum anim ...

  4. C语言学习015:联合(union)与枚举(enum)

    联合 联合和结构的区别是,结构会为每个字段申请一片内存空间,而联合只是申请了一片内存空间然后所有字段都会保存到这片空间中,这片空间的大小由字段中最长的决定,下面我们就开始定义一个联合 //联合的定义 ...

  5. GO语言学习笔记2-int类型的取值范围

    相比于C/C++语言的int类型,GO语言提供了多种int类型可供选择,有int8.int16.int32.int64.int.uint8.uint16.uint32.uint64.uint. 1.i ...

  6. TS学习随笔(二)->类型推论,联合类型

    这篇内容指南:        -----类型推论  -----联合类型 类型推论 第一篇中我们看了TS的基本使用和基本数据类型的使用,知道了变量在使用的时候都得加一个类型,那我们可不可以不加呢,这个嘛 ...

  7. 〖C语言学习笔记 〗(二) 数据类型

    前言 本文为c语言的学习笔记,很多只是留下来占位的 数据类型 助记:变量就是在内存中挖个坑并给这个坑命名,而数据类型就是挖内存的坑的尺寸 基础类型 整数类型: short int int long i ...

  8. 【转】朱兆祺教你如何攻破C语言学习、笔试与机试的难点(连载)

    原文网址:http://bbs.elecfans.com/jishu_354666_1_1.html 再过1个月又是一年应届毕业生应聘的高峰期了,为了方便应届毕业生应聘,笔者将大学四年C语言知识及去年 ...

  9. C语言学习书籍推荐《C Primer Plus(中文版)(第5版)》下载

    普拉塔 (Prata S.) (作者), 云巅工作室 (译者) <C Primer Plus(中文版)(第5版)>共17章,介绍了C语言的基础知识,包括数据类型.格式化输入输出.运算符.表 ...

随机推荐

  1. leveldb源码分析--Comparator

    既然leveldb是一个按Key序组织的LSM-Tree实现,那么对于Key的比较就是非常之重要了,这个Key的比较在leveldb中是Comparator的形式出现的.我们首先来看看Comparat ...

  2. [BZOJ 3167][HEOI 2013]SAO

    [BZOJ 3167][HEOI 2013]SAO 题意 对一个长度为 \(n\) 的排列作出 \(n-1\) 种限制, 每种限制形如 "\(x\) 在 \(y\) 之前" 或 & ...

  3. C++构造析构函数生命期及对象生命期

  4. js面对对象编程(二):属性和闭包

    上篇博客中解说了一些js对象的基本概念和使用方法.这篇博客解说一下js属性方面的:公有属性.私有属性,特权方法. 假设学过java.公有属性.私有属性,特权方法(即能够訪问和设置私有属性的方法)一定非 ...

  5. linux 的常用命令---------第八阶段

            raid 磁盘阵列-------raid 0     raid1                              raid5      raid10 mdadm 命令常用参数 ...

  6. day3-课堂代码

    # a = ('哈哈', 'xixi', 'hehe') # print(a[0]) # print(a[0:2]) # # # 列表 # a = ['哈哈', 'xixi', 'hehe', 1, ...

  7. linux网络工具iproute2的使用简介

    一.写本文的目的 本文完全是自己在学习iproute2的过程中搜集的大杂烩,记录在这里,方便以后自己查询学习,图片都是来自网络,在此表示感谢! 二.简单了解iproute2工具套装 iproute2是 ...

  8. lua连接redis集群

    连接redis集群需要用到llua-resty-redis-cluster模块 github地址:https://github.com/cuiweixie/lua-resty-redis-cluste ...

  9. 如何快速找到某个研究领域的所有SCI期刊

    https://www.toutiao.com/a6624332265285485060/?tt_from=dingtalk&utm_campaign=client_share&tim ...

  10. 学习Kali Linux必须知道的几点

    Kali Linux 在渗透测试和白帽子方面是业界领先的 Linux 发行版.默认情况下,该发行版附带了大量入侵和渗透的工具和软件,并且在全世界都得到了广泛认可.即使在那些甚至可能不知道 Linux ...