最近遇到个问题,就是通过udp收到4个字节,这4个字节表示的是一个float,由于所用plc板上的结构化文本语言(st)没有memcpy来复制内存,也没有union数据类型,因此只能自己想办法把这4个字节转为float了。
看了这篇文章:float类型的存储方式(https://zhuanlan.zhihu.com/p/82761324)清楚了float是如何转为32位二进制码的,然后就按照这个原则来将4个字节的32位二进制码转为float。
以下为C++代码:
int main()
{
float f= -123.1958;
char data[4];
//用memcpy来模拟通过比方说upd收到的4个字节
memcpy(data, &f, 4);
//合并4个单字节
int num = 0;
for(int i = 3; i >= 0; --i) // 注意区分高低位
num = (num<<8)|(data[i]&~(~0<<8)); //1001会扩展为高位全是1,因此只取后8位
bool negative_flag = num>>31;
//先取第23到30位,然后减127得到指数
int e = int((num>>23) & ~(~0<<8)) - 127; //不加类型转换int时,(num>>23) & ~(~0<<8)的数据类型是?
int tail = 1<<23 | (num & ~(~0<<23)); //取第0到22位,且23位置为1
// 去掉尾部补的0
while((tail & ~1) == tail)
{
tail = tail>>1;
}
int tmp = ~(~0<<23);
int cnt; //tail中最高位的1的位置,即不算高位0的有效的二进制位数
for(int i = 0; i < 24; ++i)
{
if((tmp & tail) == tail)
tmp = tmp>>1;
else
{
cnt = 24 - i;
break;
}
}
int integer = tail>>(cnt - e - 1); //整数部分,不用再处理了
int decimal = tail&(~(~0<<(cnt - e - 1))); //小数部分,还得再处理
float result = 0;
for(int decimal_num = cnt - e - 1; decimal_num > 0; --decimal_num)
{
// 每次循环是先加上decimal的最低位然后除2,然后decimal右移1位
result += decimal & 1;
result /= 2;
decimal = decimal >> 1;
}
result += integer;
if(negative_flag)
result = -result;
printf("%.7f\n", result);
return 0;
}