Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

float bits and strict aliasing

Tags:

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; } 
like image 703
fredoverflow Avatar asked Dec 01 '10 19:12

fredoverflow


2 Answers

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.

like image 164
Goz Avatar answered Oct 09 '22 19:10

Goz


The union hack is definitely undefined behavior, right?

Yes and no. According to the standard, it is definitely undefined behavior. But it is such a commonly used trick that GCC and MSVC and as far as I know, every other popular compiler, explicitly guarantees that it is safe and will work as expected.

like image 36
jalf Avatar answered Oct 09 '22 20:10

jalf