Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swap bits in c++ for a double

Im trying to change from big endian to little endian on a double. One way to go is to use

double val, tmp = 5.55;

((unsigned int *)&val)[0] = ntohl(((unsigned int *)&tmp)[1]);
((unsigned int *)&val)[1] = ntohl(((unsigned int *)&tmp)[0]);

But then I get a warning: "dereferencing type-punned pointer will break strict-aliasing rules" and I dont want to turn this warning off.

Another way to go is:

#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) ) 

val = (double)bswap_64(unsigned long long(tmp)); //or
val = (double)ntohll(unsigned long long(tmp));

But then a lose the decimals. Anyone know a good way to swap the bits on a double without using a for loop?

like image 210
hidayat Avatar asked Dec 22 '22 03:12

hidayat


2 Answers

I'd probably try something like this:

template <typename T>
void swap_endian(T& pX)
{
    // should static assert that T is a POD

    char& raw = reinterpret_cast<char&>(pX);
    std::reverse(&raw, &raw + sizeof(T));
}

Short and sweet (and relatively untested). The compiler will make all the necessary optimizations. The above is well-defined for any POD type, and doesn't rely on any implementation details.

A copy version, for when you don't want to modify the argument:

template <typename T>
T swap_endian_copy(T pX)
{
    swap_endian(pX);
    return pX;
}
like image 180
GManNickG Avatar answered Jan 05 '23 08:01

GManNickG


There are some important pitfalls to pay attention to when dealing with the binary representation of floats or doubles.

like image 26
Max Lybbert Avatar answered Jan 05 '23 09:01

Max Lybbert