Floating Point Concerns

Consider this simple implementation of endian_reverse:

template <class T>
inline T endian_reverse(T x) BOOST_NOEXCEPT
{
  std::reverse(reinterpret_cast<unsigned char*>(&x),
    reinterpret_cast<unsigned char*>(&x) + sizeof(T));
  return x;
}

Under what conditions with this code fail?

It will fail if an object of type T has one or more bit patterns that cause a failure. Failures usually occur when  an invalid or otherwise special bit pattern is loaded into or saved from a hardware register.

The problem could in theory occur with both integers and floating point numbers, but the two's complement integers ubiquitous in modern computer architectures do not have any invalid or otherwise special bit patterns that cause failure when byte-wise reversed.

But floating point numbers are a different story. Even if we limit discussion to IEEE 754 (aka ISO/IEC/IEEE 60559) binary representations of 4 and 8 byte sizes, several problems are easy to demonstrate:

Safe interfaces and possible reference implementations

In-place interface

template <class T>
inline void endian_reverse_inplace(T& x)
{
  std::reverse(reinterpret_cast<unsigned char*>(&x),
    reinterpret_cast<unsigned char*>(&x) + sizeof(T));
}

This is the same as the current (i.e integer) customization point interface, so there is no need for any change.

Warning: Even thought x may have had a valid value on the originating platform, after calling this function the value of x may differ or be invalid on this platform.

Copy interface

template <class T>
inline void endian_reverse_copy(const T& from, T& to)
{
  std::reverse_copy(reinterpret_cast<const unsigned char*>(&from),
    reinterpret_cast<const unsigned char*>(&from) + sizeof(T),
    reinterpret_cast<unsigned char*>(&to));
}

Warning: Even thought from may have been a valid value on the originating platform, after calling this function the value of to may differ or be invalid on this platform.

Return-by-value interface

template <class T>
inline T endian_reverse_to_native(const T& x) BOOST_NOEXCEPT
{
  T tmp;
  std::reverse_copy(reinterpret_cast<const unsigned char*>(&x),
    reinterpret_cast<const unsigned char*>(&x) + sizeof(T),
    reinterpret_cast<unsigned char*>(&tmp));
  return tmp;
}

Warning: Even thought x may have had a valid value on the originating platform, the value of returned by this function may differ or be invalid on this platform.

Acknowledgements


Last revised: 27 March, 2015

© Copyright Beman Dawes, 2015

Distributed under the Boost Software License, Version 1.0. See www.boost.org/ LICENSE_1_0.txt