Byteswapping floating point types
Andrew Haley
aph@redhat.com
Wed Jul 15 08:45:00 GMT 2009
On 07/14/2009 10:44 PM, Andrew Troschinetz wrote:
> Hi all,
>
> I'm having an argument about byteswapping floating point types and since
> the argument is mainly concerning the behavior of the compiler (and in
> this case of GCC specifically) I figure this list is a good place to ask
> for information.
>
> A co-worker has preposed this function (simplified here) for providing
> byteswaping for both integral and floating point types.
>
> template<class T>
> T byteswap(T value)
> {
> T result;
> size_t n = sizeof (T);
> unsigned char* p = (unsigned char*) &value;
> for (size_t i = 0; i < n; ++i)
> ((unsigned char*) &result)[i] = p[n - 1 - i];
> return result;
> }
>
> Now, aside from the fact that this template is _too_ generic and accepts
> things it really shouldn't, it does successfully byteswap both integral
> and floating point types. I believe that manipulating the underlying
> bytes of floating point values via access through unsigned char* should
> be safe, as opposed to a methods of byteswaping by leveraging unions
> which breaks aliasing rules.
Doing this with unions doesn't break aliasing rules on gcc.
> But for floating point types doesn't this signature run the risk of the
> compiler putting a byteswapped floating point value into an FPU
> register, thus causing the data to be modified?
Why would it? Perhaps you're concerned that loading into a FPU
register would convert a signaling NaN into a quiet NaN, or
somesuch?
> Testing with GCC 3.5.x to GCC 4.x has shown that this issue doesn't
> surface unless you attempt some mathematical operation on the float
> containing a byteswaped value. In other words:
>
> // This works
> float before = 50.125484;
> float swapped = byteswap (before);
> float after = byteswap (swapped);
> assert (before == after);
>
> // This fails
> float before = 50.125484;
> float swapped = byteswap (before);
> swapped += 0;
> float after = byteswap (swapped);
> assert (before == after);
>
> My concern is that the compiler is free to put floating point values
> into FPU registers as it sees fit and relying on the compiler not doing
> so is dangerous. He feels that my concern is misguided and if his
> implementation of byteswap() doesn't work it's because the compiler is
> broken or someone is trying to do something with byteswapped floating
> point values that they shouldn't be doing.
You're in the realm of at best implementation-defined or at worst
undefined behaviour. The CPUs I know are quite happy to do exact
copies of memory via floating-point registers, and some versions of
memcpy() make use of that. But in general it's not guaranteed.
Andrew.
More information about the Gcc-help
mailing list