简体   繁体   中英

Convert between little-endian and big-endian floats effectively

I have a working software, which currently runs on a little-endian architecture. I would like to make it run in big-endian mode too. I would like to write little-endian data into files, regardless of the endianness of the underlying system.

To achieve this, I decided to use the boost endian library. It can convert integers efficiently. But it cannot handle floats (and doubles).

It states in the documentation , that " Floating point types will be supported in the Boost 1.59.0 ". But they are still not supported in 1.62 .

I can assume, that the floats are valid IEEE 754 floats (or doubles). But their endianness may vary according to the underlying system. As far as I know, using the htonl and ntohl functions on floats is not recommended. How is it possible then? Is there any header-only library, which can handle floats too? I was not able to find any.

I could convert the floats to string, and write that into a file, I would like to avoid that method, for many reasons ( performance, disk-space, ... )

Here:

float f = 1.2f;
auto it = reinterpret_cast<uint8_t*>(&f);
std::reverse(it, it + sizeof(f)); //f is now in the reversed endianness

No need for anything fancy.

Unheilig: you are correct, but

#include <boost/endian/conversion.hpp>


template <typename T>
inline T endian_cast(const T & t)
{
#ifdef BOOST_LITTLE_ENDIAN
    return boost::endian::endian_reverse(t);
#else
    return t;
#endif
}

or when u are using pointers, to immediate reversing, use:

template <typename T>
inline T endian_cast(T *t)
{
#ifdef BOOST_LITTLE_ENDIAN
    return boost::endian::endian_reverse_inplace(*t);
#else
    return t;
#endif
}

and use it, instead of manually (or maybe error-prone) reversing it's content

example:

std::uint16_t start_address() const
{
    std::uint16_t address;
    std::memcpy(&address, &data()[1], 2);
    return endian_cast(address);
}
void start_address(std::uint16_t i)
{
    endian_cast(&i);
    std::memcpy(&data()[1], &i, 2);
}

Good luck.

When serializing float/double values, I make the following three assumptions:

  1. The machine representation follows IEEE 754
  2. The endianess of float/double matches the endianess of integers
  3. The behavior of reinterpret_cast-ing between double&/int64_t& or float&/int32_t& is well-defined (Eg, the cast behaves as if the types are similar).

None of these assumptions is guaranteed by the standard. Under these assumptions, the following code will ensure doubles are written in little-endian:

ostream out;
double someVal;
...
static_assert(sizeof(someVal) == sizeof(int64_t),
    "Endian conversion requires 8-byte doubles");
native_to_little_inplace(reinterpret_cast<int64_t&>(someVal));
out.write(reinterpret_cast<char*>(&someVal), sizeof(someVal));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM