如何以便携方式将整数转换为little-endian

时间:2016-04-14 23:16:25

标签: c++ portability endianness

我想知道以便携方式将整数转换为/从little-endian转换的推荐方法。

那有没有图书馆?

我们可以使用htonl and ntohl然后使用另一个big-endian(来自)little-endian转换,但效率不高。

2 个答案:

答案 0 :(得分:1)

便携式方法是将位移和掩码用于适当大小的字符串。注意我说的是字符串,因为这是你需要关注字节序的唯一时间 - 在系统之间传输字节时。

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

这样做的缺点是代码无法内联。以便携方式编写转换并使用模板或内联可能更有效。结合半便携式编译时检查,这与您一样好。

在编译时进一步阅读:Detecting Endianness

答案 1 :(得分:1)

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

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

然而事实证明,在gcc中,当使用-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;
}

这是在intel(little-endian)平台上编译时的汇编程序输出:

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