Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am trying to extract the bits from a float without invoking undefined behavior. Here is my first attempt:

unsigned foo(float x)
{
    unsigned* u = (unsigned*)&x;
    return *u;
}

As I understand it, this is not guaranteed to work due to strict aliasing rules, right? Does it work if a take an intermediate step with a character pointer?

unsigned bar(float x)
{
    char* c = (char*)&x;
    unsigned* u = (unsigned*)c;
    return *u;
}

Or do I have to extract the individual bytes myself?

unsigned baz(float x)
{
    unsigned char* c = (unsigned char*)&x;
    return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}

Of course this has the disadvantage of depending on endianness, but I could live with that.

The union hack is definitely undefined behavior, right?

unsigned uni(float x)
{
    union { float f; unsigned u; };
    f = x;
    return u;
}

Just for completeness, here is a reference version of foo. Also undefined behavior, right?

unsigned ref(float x)
{
    return (unsigned&)x;
}

So, is it possible to extract the bits from a float (assuming both are 32 bits wide, of course)?


EDIT: And here is the memcpy version as proposed by Goz. Since many compilers do not support static_assert yet, I have replaced static_assert with some template metaprogramming:

template <bool, typename T>
struct requirement;

template <typename T>
struct requirement<true, T>
{
    typedef T type;
};

unsigned bits(float x)
{
    requirement<sizeof(unsigned)==sizeof(float), unsigned>::type u;
    memcpy(&u, &x, sizeof u);
    return u;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
256 views
Welcome To Ask or Share your Answers For Others

1 Answer

About the only way to truly avoid any issues is to memcpy.

unsigned int FloatToInt( float f )
{
   static_assert( sizeof( float ) == sizeof( unsigned int ), "Sizes must match" );
   unsigned int ret;
   memcpy( &ret, &f, sizeof( float ) );
   return ret;
}

Because you are memcpying a fixed amount the compiler will optimise it out.

That said the union method is VERY widely supported.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...