开发者

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(unsig开发者_JS百科ned 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?


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;
}


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


Can't you just swap them around?

inline unsigned long long EndianChange( double d )
{
    char ch[8];
    memcpy( ch, &d, 8 );  // Note this will be optimised out completely by pretty much every compiler.
    ch[0] ^= ch[7] ^= ch[0] ^= ch[7]; 
    ch[1] ^= ch[6] ^= ch[1] ^= ch[6];
    ch[2] ^= ch[5] ^= ch[2] ^= ch[5];
    ch[3] ^= ch[4] ^= ch[3] ^= ch[4];

    unsigned long long dRet;
    memcpy( &dRet, ch, 8 ); // Again this will get optimised out.
    return dRet;
};

Edit: As pointed out the byte swapped double "can" get loaded into a register so that getting it back out of that register can mean the value is no longer valid so store it in a long long, 64-bit to avoid this problem.

Thats all there is to a byte swap. I'm not sure what you are trying to do but every big endian platform I've ever used uses the same encoding as little-endian just the byte order reversed. The above code will reverse the byte order for you. Pretty much any compiler will simply do the byte swap and then return the byte swapped variable and get rid of the memcpys. This is a good way to deal with aliasing issues.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜