C语言将float拆分为4个hex传输与重组
问题引出
实际的编程应用中,特别是数据传输通信等场合,需要传输float等类型的数据,而常用的数据传输形式一般为hex格式或字符串格式,通常我们会选用hex格式,更接近计算机的2进制,而这种传输方式就需要将float转换为hex格式了。
在计算机中,float占用4个字节,因此可以考虑将float拆分为4个hex格式的16进制数,完成数据传输后,接收方再将4个hex重组为float即可还原出原来的数据,这有点像数据的编码和解码的意味。
分步测试
float型的2进制形式
float的计算机中占用4个字节,具体是如何在计算机中存储的可以参考上一篇笔记:C语言打印数据的二进制格式-原理解析与编程实现,上次的int数据打印2进制的函数这里也可以用来测试,只需将参数类型改成float:
void printf_bin(float num)//注意这次这里的参数类型改成了float
{
int i, j, k;
unsigned char *p = (unsigned char*)&num + 3;
for (i = 0; i < 4; i++) //处理4个字节(32位)
{
j = *(p - i); //取每个字节的首地址
for (int k = 7; k >= 0; k--) //处理每个字节的8个位
{
if (j & (1 << k))
printf("1");
else
printf("0");
}
printf(" ");
}
printf("rn");
}
现在来测试一个float数据的2进制形式:
float a = 3.887;
//使用上次自己写的printf_bin函数打印一下float a的2进制形式
printf("查看一下float型a=%f的2进制形式:rn", a);
printf_bin(a);
//使用unsigned char来验证float的每一个字节
unsigned char *p1 = (unsigned char*)&a; //获取a的首地址
unsigned char *p2 = (unsigned char*)&a + 1;//获取a的首地址的后一个字节地址
unsigned char *p3 = (unsigned char*)&a + 2;//获取a的首地址的后两个字节地址
unsigned char *p4 = (unsigned char*)&a + 3;//获取a的首地址的后三个字节地址
printf("rn查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):rn");
printf("[a] p1:%x, %d(%x)rn", p1, *p1, *p1);//打印p1的地址与存储的字节内容
printf("[a] p2:%x, %d(%x)rn", p2, *p2, *p2);//打印p2的地址与存储的字节内容
printf("[a] p3:%x, %d(%x)rn", p3, *p3, *p3);//打印p3的地址与存储的字节内容
printf("[a] p4:%x, %d(%x)rn", p4, *p4, *p4);//打印p4的地址与存储的字节内容
输出:
查看一下float型a=3.887000的2进制形式:
01000000 01111000 11000100 10011100
查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):
[a] p1:5b5bf554, 156(9c)
[a] p2:5b5bf555, 196(c4)
[a] p3:5b5bf556, 120(78)
[a] p4:5b5bf557, 64(40)
这个输出结果实际上我们也无法直接看出拆分的到底对不对,上次测试int是对的,理论上也适用于float,因为2者都是4字节储存。
我们可以先继续拆分测试,最后重组看看是否可以还原数据。
数据拆分与重组
这里写了测试函数,先将float拆分为4个字节,保存在tbuf[0]~tbuf[3]
中,并先打印查看是否正确。如果是在实际应用中,这时就可以将4个数据以hex的形式发送出去了。
然后将数据重组,这里直接使用tbuf[0]~tbuf[3]
模拟接收方接收到的4个hex数据,将重组后的数据保存在res变量中,重组的方法也是根据float在计算机占4个字节,通过unsigned char
指针依次为float的4个字节赋值即可
void test_float_to_4hex(float num)
{
unsigned char tbuf[4];
unsigned char *p = (unsigned char*)&num + 3;//指针p先指向float的最高字节
float res;//验证float拆分为4个字节后,重组为float的结果
//先打印一下传入的float的值
printf("rn传入的float的值:%f", num);
//获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了
tbuf[0] = *(p-3);
tbuf[1] = *(p-2);
tbuf[2] = *(p-1);
tbuf[3] = *p;
//打印看一下
printf("rn查看float的每个字节内容(16进制):rn");
printf("%x,%x,%x,%xrn", tbuf[0], tbuf[1], tbuf[2], tbuf[3]);
//对拆分后的4个字节进行重组,模拟接收到hex后的数据还原过程
unsigned char *pp = (unsigned char*)&res;
pp[0] = tbuf[0];
pp[1] = tbuf[1];
pp[2] = tbuf[2];
pp[3] = tbuf[3];
printf("rn重组后的float的值:%frn", res);
}
测试一下该函数:
//模拟测试float转为4个16进制数进行数据传输的过程
test_float_to_4hex(a);
结果:
传入的float的值:3.887000
查看float的每个字节内容(16进制):
9c,c4,78,40
重组后的float的值:3.887000
数据重组后可以还原,方法是可以的。
关于int型数据
int型数据与float一样都是占用4个字节,所以该方法也适用于将int转换为4个hex,只需修改float类型为int即可:
void test_int_to_4hex(int num)
{
unsigned char tbuf[4];
unsigned char *p = (unsigned char*)&num + 3;//指针p先指向int的最高字节
int res;//验证int拆分为4个字节后,重组为float的结果
//先打印一下传入的int的值
printf("rn传入的int的值:%d", num);
//获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了
tbuf[0] = *(p - 3);
tbuf[1] = *(p - 2);
tbuf[2] = *(p - 1);
tbuf[3] = *p;
//打印看一下
printf("rn查看int的每个字节内容(16进制):rn");
printf("%x,%x,%x,%xrn", tbuf[0], tbuf[1], tbuf[2], tbuf[3]);
//对拆分后的4个字节进行重组,模拟接收到hex后的数据还原过程
unsigned char *pp = (unsigned char*)&res;
pp[0] = tbuf[0];
pp[1] = tbuf[1];
pp[2] = tbuf[2];
pp[3] = tbuf[3];
printf("rn重组后的int的值:%drn", res);
}
实测:
int b = -85776553;
test_int_to_4hex(b);
结果:
传入的int的值:-85776553
查看int的每个字节内容(16进制):
57,27,e3,fa
重组后的int的值:-85776553
完整测试代码
下面是整个本文的整个测试程序与运行结果:
#include <stdio.h>
void printf_bin(float num)//注意这次这里的参数类型改成了float
{
int i, j, k;
unsigned char *p = (unsigned char*)&num + 3;
for (i = 0; i < 4; i++) //处理4个字节(32位)
{
j = *(p - i); //取每个字节的首地址
for (int k = 7; k >= 0; k--) //处理每个字节的8个位
{
if (j & (1 << k))
printf("1");
else
printf("0");
}
printf(" ");
}
printf("rn");
}
void test_float_to_4hex(float num)
{
unsigned char tbuf[4];
unsigned char *p = (unsigned char*)&num + 3;//指针p先指向float的最高字节
float res;//验证float拆分为4个字节后,重组为float的结果
//先打印一下传入的float的值
printf("rn传入的float的值:%f", num);
//获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了
tbuf[0] = *(p-3);
tbuf[1] = *(p-2);
tbuf[2] = *(p-1);
tbuf[3] = *p;
//打印看一下
printf("rn查看float的每个字节内容(16进制):rn");
printf("%x,%x,%x,%xrn", tbuf[0], tbuf[1], tbuf[2], tbuf[3]);
//对拆分后的4个字节进行重组,模拟接收到hex后的数据还原过程
unsigned char *pp = (unsigned char*)&res;
pp[0] = tbuf[0];
pp[1] = tbuf[1];
pp[2] = tbuf[2];
pp[3] = tbuf[3];
printf("rn重组后的float的值:%frn", res);
}
void test_int_to_4hex(int num)
{
unsigned char tbuf[4];
unsigned char *p = (unsigned char*)&num + 3;//指针p先指向int的最高字节
int res;//验证int拆分为4个字节后,重组为float的结果
//先打印一下传入的int的值
printf("rn传入的int的值:%d", num);
//获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了
tbuf[0] = *(p - 3);
tbuf[1] = *(p - 2);
tbuf[2] = *(p - 1);
tbuf[3] = *p;
//打印看一下
printf("rn查看int的每个字节内容(16进制):rn");
printf("%x,%x,%x,%xrn", tbuf[0], tbuf[1], tbuf[2], tbuf[3]);
//对拆分后的4个字节进行重组,模拟接收到hex后的数据还原过程
unsigned char *pp = (unsigned char*)&res;
pp[0] = tbuf[0];
pp[1] = tbuf[1];
pp[2] = tbuf[2];
pp[3] = tbuf[3];
printf("rn重组后的int的值:%drn", res);
}
int main()
{
float a = 3.887;
//使用上次自己写的printf_bin函数打印一下float a的2进制形式
printf("查看一下float型a=%f的2进制形式:rn", a);
printf_bin(a);
//使用unsigned char来验证float的每一个字节
unsigned char *p1 = (unsigned char*)&a; //获取a的首地址
unsigned char *p2 = (unsigned char*)&a + 1;//获取a的首地址的后一个字节地址
unsigned char *p3 = (unsigned char*)&a + 2;//获取a的首地址的后两个字节地址
unsigned char *p4 = (unsigned char*)&a + 3;//获取a的首地址的后三个字节地址
printf("rn查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):rn");
printf("[a] p1:%x, %d(%x)rn", p1, *p1, *p1);//打印p1的地址与存储的字节内容
printf("[a] p2:%x, %d(%x)rn", p2, *p2, *p2);//打印p2的地址与存储的字节内容
printf("[a] p3:%x, %d(%x)rn", p3, *p3, *p3);//打印p3的地址与存储的字节内容
printf("[a] p4:%x, %d(%x)rn", p4, *p4, *p4);//打印p4的地址与存储的字节内容
//模拟测试float转为4个16进制数进行数据传输的过程
test_float_to_4hex(a);
//测试int型的转换
printf("rn该方法也有可以传输int,因为float和int在计算机中都是占4个字节,测试如下:rn");
int b = -85776553;
test_int_to_4hex(b);
return 0;
}
查看一下float型a=3.887000的2进制形式:
01000000 01111000 11000100 10011100
查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):
[a] p1:d750f694, 156(9c)
[a] p2:d750f695, 196(c4)
[a] p3:d750f696, 120(78)
[a] p4:d750f697, 64(40)
传入的float的值:3.887000
查看float的每个字节内容(16进制):
9c,c4,78,40
重组后的float的值:3.887000
该方法也有可以传输int,因为float和int在计算机中都是占4个字节,测试如下:
传入的int的值:-85776553
查看int的每个字节内容(16进制):
57,27,e3,fa
重组后的int的值:-85776553
请按任意键继续. . .
- 腾讯互联网与社会研究院秘书长司晓:将联合开展研究合作
- 幻灯片jQuery插件Orbit 介绍(附添加到WordPress教程)
- Gravatar开发者手册
- Gravatar开发者手册
- 使用Google CDN服务提供的jQuery库
- 比特币的分叉币都认为能够取代比特币,事实真的是这样吗?
- Google官方网页载入速度检测工具PageSpeed Insights 使用教程
- ASP.NET 路由
- Kafka定时清除过期数据
- 腾讯高级副总裁郭凯天:打造腾讯智库分析互联网产业前沿问题
- Google Chrome 浏览器 开发者工具 使用教程
- 反向代理(Reverse Proxy)及 IIS 7 应用请求路由模块
- 2014腾讯“大数据连接的未来”高峰论坛在京召开
- 工作流、业务流程管理和SOA
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 浙大版《C语言程序设计(第3版)》题目集 习题2-4 求交错序列前N项和
- 二十五块DIY 带屏幕可远程的温湿度传感器
- 浙大版《C语言程序设计(第3版)》题目集 习题2-5 求平方根序列前N项和
- 浙大版《C语言程序设计(第3版)》题目集 习题2-6 求阶乘序列前N项和
- 案例:ADG环境遇到redo日志member路径有误以及RMAN-6571错误
- 浙大版《C语言程序设计(第3版)》题目集 练习3-2 计算符号函数的值
- 浙大版《C语言程序设计(第3版)》题目集 练习3-3 统计学生平均成绩与及格人数
- 浙大版《C语言程序设计(第3版)》题目集 练习3-4 统计字符
- SQL 语句单引号、双引号的用法
- 浙大版《C语言程序设计(第3版)》题目集 练习3-5 输出闰年
- 浙大版《C语言程序设计(第3版)》题目集 练习3-7 成绩转换
- 浙大版《C语言程序设计(第3版)》题目集 练习3-8 查询水果价格
- 浙大版《C语言程序设计(第3版)》题目集 习题3-1 比较大小
- 浙大版《C语言程序设计(第3版)》题目集 习题3-3 出租车计价
- 浙大版《C语言程序设计(第3版)》题目集 习题3-4 统计学生成绩