2016-04-14 57 views
1

我想知道以便携方式将整数转换成小尾数的推荐方式是什么。如何将整数以便携方式转换为小尾数

是否有任何图书馆?

我们可以使用htonl and ntohl,然后做一个大端到小端的转换,但效率不高。

+0

你想达到什么目的?除非你做了一些时髦的转换和取消指向各种大小整数的指针,否则你不需要担心endianess。另请参阅[“htonl()vs __builtin_bswap32()”](http://stackoverflow.com/questions/21527957/htonl-vs-builtin-bswap32)上的这个问题,它讨论了字节交换数字的替代方法。 – Jens

+2

如果你不得不摆弄end,,你已经踏上了“不便携”的境界。因此,以这样一种方式来隔离它,其余代码可以使用适当的抽象,并且针对特定平台实现*** ***平台特定的实现。 –

回答

1

可移植的方式是使用位移和掩码到适当大小的字符串中。注意我说的是字符串,因为这实际上是唯一需要关注字节顺序的时候 - 在系统之间传输字节。

如果你想避免不必要的转换(例如在小端架构上转换成小端),那么编译时就没有完全可移植的方法。但是您可以在运行时检查以动态选择一组转换函数。

这确实有代码不能内联的缺点。以便携方式编写转换并使用模板或内联可能会更有效。结合半可移植的编译时检查,这与你会得到的一样好。

更多阅读:Detecting Endianness在编译时。

+0

该链接中的解决方案实际上不工作/不便携。事实证明,将整数转换为constexpr上下文中的字节序列是非法的,无论是通过显式转换还是联合。 –

1

这是一个很好的问题。它促使我看看是否有任何方法可以在编译时使用constexpr表达式来确定字节序。

事实证明,如果没有预处理技巧,这是不可能的,因为在constexpr上下文中评估时,无法将整数转换为字节序列(通过强制转换或联合)。

然而事实证明,在海湾合作委员会,与-O2编译一个简单的运行时检查被优化掉,所以这实际上是最为有效的:

#include <cstdint> 
#include <iostream> 

constexpr bool is_little_endian() 
{ 
    union endian_tester { 
     std::uint16_t n; 
     std::uint8_t p[4]; 
    }; 

    constexpr endian_tester sample = {0x0102}; 
    return sample.p[0] == 0x2; 
} 

template<class Int> 
Int to_little_endian(Int in) 
{ 
    if (is_little_endian()) { 
    return in; 
    } 
    else { 
    Int out = 0; 
    std::uint8_t* p = reinterpret_cast<std::uint8_t*>(std::addressof(out)); 
    for (std::size_t byte = 0 ; byte < sizeof(in) ; ++byte) 
    { 
     auto part = (in >> (byte * 8)) & 0xff; 
     *p++ = std::uint8_t(part); 
    } 

    return out; 
    } 
} 

int main() 
{ 
    auto x = to_little_endian(10); 
    std::cout << x << std::endl; 
} 

这里编译就当是汇编输出。一个英特尔(小端)平台:

main: 
     subq $8, %rsp 
# 
# here is the call to to_little_endian() 
# 

     movl $10, %esi 
# 
# that was it - it's been completely optimised away 
# 

     movl std::cout, %edi 
     call std::basic_ostream<char, std::char_traits<char> >::operator<<(int) 
     movq %rax, %rdi 
     call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&) 
     xorl %eax, %eax 
     addq $8, %rsp 
     ret