问题引出
实际的编程应用中,特别是数据传输通信等场合,需要传输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("\r\n");}

现在来测试一个float数据的2进制形式:

float a = 3.887;//使用上次自己写的printf_bin函数打印一下float a的2进制形式printf("查看一下float型a=%f的2进制形式:\r\n", 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("\r\n查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):\r\n");printf("[a] p1:%x, %d(%x)\r\n", p1, *p1, *p1);//打印p1的地址与存储的字节内容printf("[a] p2:%x, %d(%x)\r\n", p2, *p2, *p2);//打印p2的地址与存储的字节内容printf("[a] p3:%x, %d(%x)\r\n", p3, *p3, *p3);//打印p3的地址与存储的字节内容printf("[a] p4:%x, %d(%x)\r\n", 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("\r\n传入的float的值:%f", num);    //获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了    tbuf[0] = *(p-3);    tbuf[1] = *(p-2);    tbuf[2] = *(p-1);    tbuf[3] = *p;    //打印看一下    printf("\r\n查看float的每个字节内容(16进制):\r\n");    printf("%x,%x,%x,%x\r\n", 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("\r\n重组后的float的值:%f\r\n", 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("\r\n传入的int的值:%d", num);    //获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了    tbuf[0] = *(p - 3);    tbuf[1] = *(p - 2);    tbuf[2] = *(p - 1);    tbuf[3] = *p;    //打印看一下    printf("\r\n查看int的每个字节内容(16进制):\r\n");    printf("%x,%x,%x,%x\r\n", 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("\r\n重组后的int的值:%d\r\n", 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("\r\n");}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("\r\n传入的float的值:%f", num);    //获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了    tbuf[0] = *(p-3);    tbuf[1] = *(p-2);    tbuf[2] = *(p-1);    tbuf[3] = *p;    //打印看一下    printf("\r\n查看float的每个字节内容(16进制):\r\n");    printf("%x,%x,%x,%x\r\n", 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("\r\n重组后的float的值:%f\r\n", 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("\r\n传入的int的值:%d", num);    //获取对应的4个字节,从低位到高位,这时就可以用于hex格式的数据传输了    tbuf[0] = *(p - 3);    tbuf[1] = *(p - 2);    tbuf[2] = *(p - 1);    tbuf[3] = *p;    //打印看一下    printf("\r\n查看int的每个字节内容(16进制):\r\n");    printf("%x,%x,%x,%x\r\n", 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("\r\n重组后的int的值:%d\r\n", res);}int main(){    float a = 3.887;    //使用上次自己写的printf_bin函数打印一下float a的2进制形式    printf("查看一下float型a=%f的2进制形式:\r\n", 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("\r\n查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):\r\n");    printf("[a] p1:%x, %d(%x)\r\n", p1, *p1, *p1);//打印p1的地址与存储的字节内容    printf("[a] p2:%x, %d(%x)\r\n", p2, *p2, *p2);//打印p2的地址与存储的字节内容    printf("[a] p3:%x, %d(%x)\r\n", p3, *p3, *p3);//打印p3的地址与存储的字节内容    printf("[a] p4:%x, %d(%x)\r\n", p4, *p4, *p4);//打印p4的地址与存储的字节内容    //模拟测试float转为4个16进制数进行数据传输的过程    test_float_to_4hex(a);    //测试int型的转换    printf("\r\n该方法也有可以传输int,因为float和int在计算机中都是占4个字节,测试如下:\r\n");    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请按任意键继续. . .
©著作权归作者所有:来自51CTO博客作者mb5fdb1021b5992的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. Linux与Windows间文件互传之TFTP方式
  2. 【mysql】ipv4地址转换为4字节整数
  3. 【java】面试官问我,如何实现一个自定义序列化
  4. 初识指针
  5. Java与php的一些关联
  6. 追了多年的开发框架,你还认识指针吗?
  7. 还不明白可空类型原理? 我可要挖到底了
  8. Linux学习笔记总结(九十二)
  9. 字节三面:详解一条 SQL 的执行过程

随机推荐

  1. 安卓报错:java.lang.RuntimeException: Un
  2. android webview 截图快照
  3. Android 隐藏显示键盘
  4. Android JB 4.2 中InputManager 启动过程
  5. Android(安卓)应用图标库icons与icons PS
  6. Android利用WindowManager实现悬浮窗
  7. Android Studio Gradle相关异常记录
  8. 笔记——Android 中的小细节
  9. AndroidManifest.xml文件详解(service)
  10. 【Android】Wifi管理与应用