在c ++中交换位为double

时间:2010-04-20 07:42:34

标签: c++ floating-point double bits endianness

我试图在双尾上从大端改为小端。一种方法是使用

double val, tmp = 5.55;

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

但后来我收到警告:“取消引用类型惩罚指针将破坏严格别名规则”,我不想关闭此警告。

另一种方法是:

#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));

然后输掉小数。 任何人都知道在不使用for循环的情况下交换双位的好方法吗?

3 个答案:

答案 0 :(得分:9)

我可能会尝试这样的事情:

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

短而甜(并且相对未经测试)。编译器将进行所有必要的优化。以上是针对任何POD类型定义良好的,并且不依赖于任何实现细节。

副本版本,用于不想修改参数时:

template <typename T>
T swap_endian_copy(T pX)
{
    swap_endian(pX);
    return pX;
}

答案 1 :(得分:2)

在处理浮点数或双精度数的二进制表示时有some important pitfalls to pay attention to

答案 2 :(得分:0)

你不能只是交换它们吗?

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

编辑:正如所指出的,字节交换双“can”被加载到一个寄存器中,以便从该寄存器中取回它可能意味着该值不再有效所以将它存储在一个很长的64位以避免这个问题。

这就是所有的字节交换。我不确定你要做什么,但是我曾经使用过的每个大端平台都使用与little-endian相同的编码,只是字节顺序颠倒了。上面的代码将颠倒你的字节顺序。几乎任何编译器都会简单地执行字节交换,然后返回字节交换变量并删除memcpys。这是处理别名问题的好方法。