I'm receiving a buffer from a network which was converted to an array of 32-bit words. I have one word which is defined as an IEEE-754 float by my interface document. I need to extract this word from the buffer. It's tough to cast from one type to another without invoking a conversion. The bits are already adhere to the IEEE-754 float standard, I don't want to re-arrange any bits.
My first try was to cast the address of the uint32_t
to a void*
, then convert the void*
to a float*
, then dereference as a float
:
float ieee_float(uint32_t f)
{
return *((float*)((void*)(&f)));
}
error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
My second try was like this:
float ieee_float(uint32_t f)
{
union int_float{
uint32_t i;
float f;
} tofloat;
tofloat.i = f;
return tofloat.f;
}
However, word on the street is that unions are totally unsafe. It's undefined behavior to read from the member of the union that wasn't most recently written.
So I tried a more C++ approach:
float ieee_float(uint32_t f)
{
return *reinterpret_cast<float*>(&f);
}
error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
My next thought was "screw it. Why am I dealing with pointers anyways?" and just tried:
float ieee_float(uint32_t f)
{
return reinterpret_cast<float>(f);
}
error: invalid cast from type ‘uint32_t {aka unsigned int}’ to type ‘float’
Is there a way to do the conversion without triggering the warning/error? I'm compiling with g++ using -Wall -Werror
. I'd prefer to not touch compiler settings.
I tagged C because a c-solution is acceptable.
sizeof(float) != sizeof(std::uint32_t)
? – Ormefloat ieee_float(uint32_t f) { void *p = &f; float fv = *(float*)p; return fv; }
but theunion
is cleanertypedef union { float f; uint32_t v; } fu;
thenfloat ieee_float(uint32_t f) { fu.v = f; return fu.f; }
– Jezreel