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]
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 struct requirement; template struct requirement { typedef T type; }; unsigned bits(float x) { requirement::type u; memcpy(&u, &x, sizeof u); return u; }