From: Matt Gruenke (mgruenke_at_[hidden])
Date: 2006-10-15 04:03:09
John Maddock wrote:
>2) I'm a little surprised at seeing memcpy used to shift 4 bytes, given the
>slightly-hairy nature of what you're doing here, I don't think a
>reinterpret_cast to uint32 is unreasonable in comparison. But that's just
>my opinion :-)
Here's little tip about that. Some compilers (GCC 3.x, for example)
don't perform dataflow analysis between certain pairs of types.
Therefore, reading the bits of a float as an unsigned int by a construct
unsigned int x_bits = *reinterpret_cast< unsigned int * >( &x )
(or the reverse) may not generate all of the proper data dependencies.
What's really pernicious about this is that because the bug is
scheduling-dependent, inline functions which use these constructs may
only fail in some cases.
The reason compilers do this is because always making conservative
decisions about aliasing yields slow code (lots of extra loads &
stores). Because certain classes of aliasing are extremely rare (such
as the same memory being accessed through both an int * and float *),
such cases are excluded from alias analysis.
In the case of GCC 3.x, it seems unions avoid this problem. You can
also use __attribute__((__may_alias__)).
Here's what I used, in my optimized floating-point operations:
#define MAY_ALIAS __attribute__ ((may_alias))
typedef unsigned int uint32;
typedef uint32 MAY_ALIAS FloatBits;
//! Returns the binary representation of a single-precision
float as a uint32.
inline FloatBits Float_GetBits(
const float *p_f //!< Address of value to return.
return *reinterpret_cast< const FloatBits * >( p_f );
Yes, I learned all of this the hard way. ...and was that ever a fun bug
to track down! The odd thing is that the error seemed to be not only
context-dependent, but also non-deterministic (perhaps based on the
value of a not-yet-written memory location?)!
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk