float f;
memcpy(&f, i, sizeof f);
Don't worry about the implied overhead of the call to memcpy; the compiler will replace it with an intrinsic and emit the expected movss instruction.Back in my C++ days, I would much prefer pointer-cast to union-struct, because the latter was subject to alignment/padding issues you mention, while for the former, I know of no desktop architecture that could mess up a int* -> float* cast.
I'm also doubly surprised because being able to do that stuff is what I'd consider the selling point of C/C++ over higher-level languages.
Yeah, C and C++ aren't the language most people think they are, and the strict aliasing rules are the most clear manifestation of that.
The replacement is often "gcc with inline assembly" or "gcc with lots of __attribute__ extensions such as __may_alias__" or "gcc with optimizations disabled".
The need doesn't go away, despite the wishes of a language committee now dominated by compiler suppliers. From day 1, long before the language was standardized and even before the original (not ANSI) book was published, C was being used with aliasing. It was, after all, developed to support the creation of Unics (before that became UNIX).
> Accessing an object by means of any other lvalue expression (other than unsigned char) is undefined behavior
https://wiki.sei.cmu.edu/confluence/display/c/EXP39-C.+Do+no...
That said, memcpy and a compiler that understand the memcpy intrinsic is probably safer; that said I have a vague memory of hitting an embedded compiler where memcpy wasn't an intrinsic
union { int i; float f;} u; u.i=*i;
Now u.f contains the same bit pattern as the integer pointed to by "i" but interpreted as a float.
Compilers know how to generate code efficiently out of this.
Iirc this is implementation defined behavior, e.g. things like endianness alignment or padding, but it's not undefined behavior, whose evil effects can bubble up in unexpected parts of the program that apparently don't even touch the bad cast.