1
A
回答
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
你想达到什么目的?除非你做了一些时髦的转换和取消指向各种大小整数的指针,否则你不需要担心endianess。另请参阅[“htonl()vs __builtin_bswap32()”](http://stackoverflow.com/questions/21527957/htonl-vs-builtin-bswap32)上的这个问题,它讨论了字节交换数字的替代方法。 – Jens
如果你不得不摆弄end,,你已经踏上了“不便携”的境界。因此,以这样一种方式来隔离它,其余代码可以使用适当的抽象,并且针对特定平台实现*** ***平台特定的实现。 –