- 1、问题描述
- 2、问题定位
- 3、问题解决
- 参考链接
1、问题描述
在项目中,需要从遥控指令中获取4字节的物体坐标X轴信息,并存储于一个float变量tmp中。物体坐标X轴原始数据为int型,存在负数,遥控指令中的数是加上了2^31,并按照unsigned int类型存储于遥控指令中,因此获取到数据后,还需要减去2^31作为最终值。
代码的逻辑如下:
(1)获取4字节,存储于float变量tmp中
(2)tmp减去2^31,并存储于float变量position_x中
但是程序中的position_x最终得到1个错误值。
2、问题定位
本文使用的获取浮点数的函数为FLOAT_GET
,函数的定义如下:
inline void FLOAT_GET(float* output, unsigned char* pvbuf)
{unsigned int data;data = ((pvbuf[0x00] << 0x18) | (pvbuf[0x01] << 0x10) | (pvbuf[0x02] << 0x08) | (pvbuf[0x03] << 0x00));*output = *(float*)(&data);
}
首先在电脑上,验证了函数的正确性。可以从字符数组中“还原”出正确的float型变量。
然后通过打断点等方式,观察到FLOAT_GET
得到的output变量显示为Nan,也就是没有获取到正确的数值,在这一步错误的话,后续减去2^31得到的结果也不会是正确值。
最后与其他同事交流,遥控指令中的X轴坐标信息是unsigned int型变量,并不是float类型,不能用float类型去“理解”4字节的数据。而代码中是获取到内存指针&data
后,将内存指针强制转换为float*
型,并按照float类型赋值给*output
变量。
总的来说,这并不是将unsigned int类型的变量赋值给float类型的变量,而是按照float类型去“解释”4字节数据。
如下图所示,32位的float型的内存分布如图所示,如果按照这种分区去“解释”4字节的unsigned int类型的数据,是得不到正确的数值的。
3、问题解决
问题定位后就比较好解决了。这个问题的出现在于没有认真地阅读通信协议,并且没有对于整型和浮点型在内存存储形式不相同的敏感性。
不使用之前的FLOAT_GET
,将代码逻辑修改为获取4字节组合成unsigned int数据类型,减去2^31后,再赋值给float型变量。程序可以正常运行了。
另外,虽然本文没有出现问题,但unsigned int转化为float是存在精度损失的,因为float可以表示的范围比unsigned int小。看来类型转换也有很多坑啊…
参考链接
【1】float类型在内存中的存储方式
float类型在内存中的存储方式_float在内存中如何存储-CSDN博客
(https://blog.csdn.net/qincjun/article/details/140592584)