Swap bits in c++ for a double

三世轮回 提交于 2019-12-22 08:59:29

问题


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?


回答1:


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



回答2:


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




回答3:


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.



来源:https://stackoverflow.com/questions/2673409/swap-bits-in-c-for-a-double

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!