4

我试图在双精度上从大端变为小端。一种方法是使用

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 循环的情况下交换双精度位的好方法吗?

4

3 回答 3

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;
}
于 2010-04-20T08:06:17.807 回答
2

在处理浮点数或双精度数的二进制表示时,需要注意一些重要的陷阱。

于 2010-04-20T08:18:28.133 回答
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;
};

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

这就是字节交换的全部内容。我不确定您要做什么,但是我曾经使用过的每个大端平台都使用与小端相同的编码,只是颠倒了字节顺序。上面的代码将为您反转字节顺序。几乎任何编译器都会简单地进行字节交换,然后返回字节交换变量并摆脱 memcpys。这是处理混叠问题的好方法。

于 2010-04-20T07:59:41.650 回答