2010-04-20 172 views
4

我试图在double上从big endian变成little endian。去的一种方法是使用在C++中交换双倍数据位

double val, tmp = 5.55; 

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

但后来我收到了警告:“提领类型punned指针将打破严格走样规则”,我不希望关闭此警告。

另一种方式去就是:

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

+1

如果你这样做在C++中,我相信你应该避免C-风格的转换。 – ereOn 2010-04-20 07:49:15

+0

昨天我类似的问题,你可能会感兴趣的答案(http://stackoverflow.com/questions/2667225/endianness-conversion-and-g-warnings) – 2010-04-20 07:54:36

+0

我查了你的问题的答案和解决方案OK,对我来说,谢谢 – hidayat 2010-04-20 08:23:33

回答

8

我可能会尝试这样的事:

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

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

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

+0

这个解决方案绝对不行 - 一个endian-changed的double可能不再是一个有效的FP值,并且会导致FPU中未定义的行为。请参阅@Max Lybbert的链接。 – stusmith 2010-04-20 10:57:35

+0

好点...固定。 – Goz 2010-04-20 11:12:50