优秀的编程知识分享平台

网站首页 > 技术文章 正文

【C编程问题集中营】在不同编译器下float强转为无符号int的表现

nanyue 2025-03-26 14:47:28 技术文章 8 ℃

一、问题背景

两个ECU之间通过某种通信方式按照某种协议进行交互时,如果需要发送的数据是单精度浮点类型的负数,一般我们会通过以下两种方式对数据进行处理然后发送:

发送端在原数据的基础上加上固定的offset正值,使之转化为单精度浮点类型的正数后,强转为无符号整型进行发送,然后接收端将数据强转为单精度浮点类型后减去固定的offset正值就基本得到一定精度的数据了。(暂不考虑小数点后的精度)

发送端将原数据也就是单精度浮点类型的负数通过一定的强转手段直接转换成无符号整型,然后进行发送,接收端接收到这个无符号整型数据后先强转为有符号整型再转换为单精度浮点类型,即可得到一定精度的原始数据了。(暂不考虑小数点后的精度)

上述第一种方法只要是offset设置的合理理论上不存在什么问题,本文主要描述的问题主要是出现在第二种方法;

当采用第二种方法进行有符号类型数据的传输时,单精度浮点类型的数据在直接强转为无符号整型时,不同编译器下的表现是不同的,下面分别用gcc以及ghs编译器进行测试;

二、测试代码以及测试结果

2.1 gcc编译测试以及结果

测试源码如下:

#include "stdio.h"
 
int main(void)
{
    float Float32TypeData      = -0.25f;
    unsigned int Int32TypeData = 0;
 
    Int32TypeData = (unsigned int)(Float32TypeData * 10000.0f);
    printf("Int32TypeData = 0x%x\r\n", Int32TypeData);
 
    return 0;
}

用gcc编译器编译后输出的结果Int32TypeData = 0xfffff63c,由此可见当此数据传输给接收端后,接收端经过两次类型的强转即可得到一定精度的原始数据。

2.2 ghs编译测试以及结果

第一次测试源码如下:(与gcc编译时的源码相同)

#include "stdio.h"
 
int main(void)
{
    float Float32TypeData      = -0.25f;
    unsigned int Int32TypeData = 0;
 
    Int32TypeData = (unsigned int)(Float32TypeData * 10000.0f);
    printf("Int32TypeData = 0x%x\r\n", Int32TypeData);
 
    return 0;
}

用ghs编译器编译后输出的结果Int32TypeData = 0x0,由此可以看出此数据直接被转换成了0,所以导致有效数据的丢失。

第二次测试源码如下:

#include "stdio.h"
 
int main(void)
{
    float Float32TypeData      = -0.25f;
    unsigned int Int32TypeData = 0;
 
    Int32TypeData = (unsigned int)((signed int)(Float32TypeData * 10000.0f));
    printf("Int32TypeData = 0x%x\r\n", Int32TypeData);
 
    return 0;
}

与第一次的区别在于在强转类型时加了一次有符号整型的强转,然后在强转为无符号的整型,这时用ghs编译器编译后输出的结果就变成了Int32TypeData = 0xfffff63c,这时再把数据传输给接收端,接收端就不会丢失有效数据了。

2.3 差异点排查

通过对比ghs前后两次生成的汇编代码,发现强转时用的汇编指令不一样,应该就是导致有差异的根本原因; 第一次测试:trncf.suw r1,r1 第二次测试:trncf.sw r1,r1 具体这两个指令有什么区别本文就不详细介绍了,可以自己去查找汇编指令手册;

三、结论

从上述测试可以得出,不同编译器在处理浮点类型的负数强转成无符号整型时表现是不一样的,所以这里小编建议要么就采用第一种方法,要不然就加一次有符号整型类型的强转。



"如果你喜欢这篇文章,请关注我们,未来还有更多精彩等着你。"

最近发表
标签列表