问题引出
实际的编程应用中,特别是数据传输通信等场合,需要传输float等类型的数据,而常用的数据传输形式一般为hex格式或字符串格式,通常我们会选用hex格式,更接近计算机的2进制,而这种传输方式就需要将float转换为hex格式了。
在计算机中,float占用4个字节,因此可以考虑将float拆分为4个hex格式的16进制数,完成数据传输后,接收方再将4个hex重组为float即可还原出原来的数据,这有点像数据的编码和解码的意味。
分步测试
float型的2进制形式
float的计算机中占用4个字节,具体是如何在计算机中存储的可以参考上一篇笔记:C语言打印数据的二进制格式-原理解析与编程实现,上次的int数据打印2进制的函数这里也可以用来测试,只需将参数类型改成float:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void printf_bin(float num) { int i, j, k; unsigned char *p = (unsigned char*)&num + 3;
for (i = 0; i < 4; i++) { j = *(p - i); for (int k = 7; k >= 0; k--) { if (j & (1 << k)) printf("1"); else printf("0"); } printf(" "); } printf("\r\n"); }
|
现在来测试一个float数据的2进制形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| float a = 3.887;
printf("查看一下float型a=%f的2进制形式:\r\n", a); printf_bin(a);
unsigned char *p1 = (unsigned char*)&a; unsigned char *p2 = (unsigned char*)&a + 1; unsigned char *p3 = (unsigned char*)&a + 2; unsigned char *p4 = (unsigned char*)&a + 3; printf("\r\n查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):\r\n"); printf("[a] p1:%x, %d(%x)\r\n", p1, *p1, *p1); printf("[a] p2:%x, %d(%x)\r\n", p2, *p2, *p2); printf("[a] p3:%x, %d(%x)\r\n", p3, *p3, *p3); printf("[a] p4:%x, %d(%x)\r\n", p4, *p4, *p4);
|
输出:
1 2 3 4 5 6 7 8
| 查看一下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个字节赋值即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| void test_float_to_4hex(float num) { unsigned char tbuf[4]; unsigned char *p = (unsigned char*)&num + 3; float res;
printf("\r\n传入的float的值:%f", num);
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]);
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); }
|
测试一下该函数:
结果:
1 2 3 4 5
| 传入的float的值:3.887000 查看float的每个字节内容(16进制): 9c,c4,78,40
重组后的float的值:3.887000
|
数据重组后可以还原,方法是可以的。
关于int型数据
int型数据与float一样都是占用4个字节,所以该方法也适用于将int转换为4个hex,只需修改float类型为int即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| void test_int_to_4hex(int num) { unsigned char tbuf[4]; unsigned char *p = (unsigned char*)&num + 3; int res;
printf("\r\n传入的int的值:%d", num);
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]);
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); }
|
实测:
1 2
| int b = -85776553; test_int_to_4hex(b);
|
结果:
1 2 3 4 5
| 传入的int的值:-85776553 查看int的每个字节内容(16进制): 57,27,e3,fa
重组后的int的值:-85776553
|
完整测试代码
下面是整个本文的整个测试程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| #include <stdio.h>
void printf_bin(float num) { int i, j, k; unsigned char *p = (unsigned char*)&num + 3;
for (i = 0; i < 4; i++) { j = *(p - i); for (int k = 7; k >= 0; k--) { 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; float res;
printf("\r\n传入的float的值:%f", num);
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]);
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; int res;
printf("\r\n传入的int的值:%d", num);
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]);
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("查看一下float型a=%f的2进制形式:\r\n", a); printf_bin(a);
unsigned char *p1 = (unsigned char*)&a; unsigned char *p2 = (unsigned char*)&a + 1; unsigned char *p3 = (unsigned char*)&a + 2; unsigned char *p4 = (unsigned char*)&a + 3; printf("\r\n查看a的每个字节的地址(16进制)与内容(10进制(+16进制)):\r\n"); printf("[a] p1:%x, %d(%x)\r\n", p1, *p1, *p1); printf("[a] p2:%x, %d(%x)\r\n", p2, *p2, *p2); printf("[a] p3:%x, %d(%x)\r\n", p3, *p3, *p3); printf("[a] p4:%x, %d(%x)\r\n", p4, *p4, *p4);
test_float_to_4hex(a);
printf("\r\n该方法也有可以传输int,因为float和int在计算机中都是占4个字节,测试如下:\r\n"); int b = -85776553; test_int_to_4hex(b);
return 0; }
|
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 查看一下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 请按任意键继续. . .
|