C语言 可以将无符号的 int 位值复制为浮点数,但浮点值未正确返回给调用方函数



在下面的代码中,我bits正确的(它最初是bits<float>程序中键入C++,但我只是在这个 C 程序中使用了uint32。我想将这些位用作 ieee754float值。只分配float_var = int_val不会这样做,因为它会解释值并强制转换为float。我只想将位值用作浮点值。

uint32 bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10];
ab_printf("bits = %xn", bits);
float out;
//memcpy(&out, &bits, sizeof(float));  // original
char *outp = &out;
char *bitsp  = &bits;
outp[0] = bitsp[0];
outp[1] = bitsp[1];
outp[2] = bitsp[2];
outp[3] = bitsp[3];
ab_printf("out = %xn", out);
return out;

部分程序运行结果:

ff = 3.140000
hh = 4248
bits = 40490000
out = 40092000

一定有一些我不知道的基本东西。 供您参考,上面的运行是将浮点数3.14转换为半精度,然后再转回单精度,我打印了中间值。0x4248是半精度3.140625和位0x40490000是单精度也3.140625,所以我只需要将其作为float返回。

补充:在阅读评论和答案后,我做了一些实验,发现在函数内部看到的单浮点值是正确的(使用指针使用类型双关语,或使用联合(,但是当它返回到调用函数时,它没有正确打印。 方法0~3都不起作用。内联函数与否没有任何区别。我们的系统中可能有另一个故障(嵌入式裸机(,但希望有人能告诉我这里可能出了什么问题。(我在这里的 C 程序中使用C++程序的一部分(。(ldexp,ldexpf 不起作用(。

== 半小时 ==

typedef unsigned short uint16;
typedef unsigned short half;
extern uint16 float2half_impl(float value);
extern float half2float_impl(half value);

== 测试4.c ==

#include "half.h"
int main()
{
float vflt = 3.14;
half vhlf;
float vflt2;
ab_printf("vflt = %fn", vflt);
vhlf = float2half_impl(vflt);
ab_printf("vhlf = %xn", *(unsigned short *)&vhlf);
float vflt2 = half2float_impl(vhlf);
ab_printf("received : vflt2 = %fn", vflt2);
}

== 一半 ==

#include "half.h"
....
inline float half2float_impl(uint16 value)
{
//typedef bits<float>::type uint32;
typedef unsigned int uint32;
static const uint32 mantissa_table[2048] = {
....
uint32 bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10];
ab_printf("bits = %xn", bits);
float out;
#define METHOD 3
#if METHOD == 0
memcpy(&out, &bits, sizeof(float));
return out;
#elif METHOD == 1
#warning METHOD 1
ab_printf("xx = %fn", *(float *)&bits); // prints 3.140625
return bits;
#elif METHOD == 2 // prints float ok but return value float prints wrong
#warning METHOD 2
union {
unsigned int ui;
float xx;
} aa;
aa.ui = bits;
ab_printf("xx = %fn", aa.xx); // prints 3.140625
return (float)aa.xx; // but return values prints wrong
#elif METHOD == 3 // prints float ok but return value float prints wrong
#warning METHOD 3
ab_printf("xx = %fn", *(float *)&bits); // prints 3.140625
return *(float *)&bits; // but return values prints wrong
#else
#warning returning 0
return 0;
#endif
}

使用联合怎么样?

union uint32_float_union
{
uint32_t i;
float    f;
};

然后你可以做一些类似的事情

union uint32_float_union int_to_float;
int_to_float.i = bits;
printf("float value = %fn", int_to_float.f);

C 规范明确允许对类型双关使用联合。

您注释掉的memcpy方式应该有效,但确实打破了严格的混叠。不过,您可以使用字节缓冲区作为中间:

char buffer[sizeof(float)];
memcpy(buffer, &bits, sizeof(float));
float value;
memcpy(&value, buffer, sizeof(float));

当然,所有这些都要求bits中的值实际上对应于有效的float值(包括正确的字节序(。

这个:

out = *(float *)&bits;

允许您使用指针魔术将bits作为float读取,而无需进行任何显式或隐式转换。

但是,请注意,endinaness可能会让您这样做有点搞砸(就像memcpy()一样,所以如果它对您有用,此方法也应该有效,但请记住,这可能会因架构而异(。

如果您可以确定uint32_t的值完全包含IEEE754二进制32的位模式,则可以通过使用ldexp()函数"构造"您的float数字,而无需您的uint32_t不包含填充或您的float实际上符合IEEE754(IOW,相当便携(。

这里有一个小例子..注意它不支持次正规数,NaNinf;添加它们是一些工作,但可以完成:

#include <stdint.h>
#include <math.h>
// read IEEE754 binary32 representation in a float
float toFloat(uint32_t bits)
{
int16_t exp = (bits >> 23 & 0xff) - 0x96;
// subtracts exponent bias (0x7f) and number of fraction bits (0x17)
int32_t sig = (bits & UINT32_C(0x7fffff)) | UINT32_C(0x800000);
if (bits & UINT32_C(0x80000000)) sig *= -1;
return ldexp(sig, exp);
}

(您可以执行类似操作,从包含半精度表示的uint16_t创建float,只需调整常量以选择正确的位(

最新更新