如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
当前回答
我只是想在这里添加我自己的解,因为我在任何地方都没有看到它。它是一个小而可移植的c++模板函数,并且只使用比特操作。
template<typename T> inline static T swapByteOrder(const T& val) {
int totalBytes = sizeof(val);
T swapped = (T) 0;
for (int i = 0; i < totalBytes; ++i) {
swapped |= (val >> (8*(totalBytes-i-1)) & 0xFF) << (8*i);
}
return swapped;
}
其他回答
从大端序到小端序的过程与从小端序到大端序的过程是一样的。
下面是一些示例代码:
void swapByteOrder(unsigned short& us)
{
us = (us >> 8) |
(us << 8);
}
void swapByteOrder(unsigned int& ui)
{
ui = (ui >> 24) |
((ui<<8) & 0x00FF0000) |
((ui>>8) & 0x0000FF00) |
(ui << 24);
}
void swapByteOrder(unsigned long long& ull)
{
ull = (ull >> 56) |
((ull<<40) & 0x00FF000000000000) |
((ull<<24) & 0x0000FF0000000000) |
((ull<<8) & 0x000000FF00000000) |
((ull>>8) & 0x00000000FF000000) |
((ull>>24) & 0x0000000000FF0000) |
((ull>>40) & 0x000000000000FF00) |
(ull << 56);
}
我喜欢这个,只是为了风格:-)
long swap(long i) {
char *c = (char *) &i;
return * (long *) (char[]) {c[3], c[2], c[1], c[0] };
}
来这里寻找一个Boost解决方案,失望地离开,但最终在其他地方找到了它。你可以使用boost::endian::endian_reverse。它被模板化/重载了所有的基元类型:
#include <iostream>
#include <iomanip>
#include "boost/endian/conversion.hpp"
int main()
{
uint32_t word = 0x01;
std::cout << std::hex << std::setfill('0') << std::setw(8) << word << std::endl;
// outputs 00000001;
uint32_t word2 = boost::endian::endian_reverse(word);
// there's also a `void ::endian_reverse_inplace(...) function
// that reverses the value passed to it in place and returns nothing
std::cout << std::hex << std::setfill('0') << std::setw(8) << word2 << std::endl;
// outputs 01000000
return 0;
}
示范
虽然,看起来c++23最终用std::byteswap解决了这个问题。(我使用的是c++17,所以这不是一个选项。)
有一个叫做BSWAP的汇编指令可以帮你做交换,非常快。 你可以在这里阅读。
Visual Studio,或者更准确地说是Visual c++运行时库,为此提供了平台intrinsic,称为_byteswap_ushort()、_byteswap_ulong()和_byteswap_int64()。其他平台应该也有类似的情况,但我不知道它们会被称为什么。
void writeLittleEndianToBigEndian(void* ptrLittleEndian, void* ptrBigEndian , size_t bufLen )
{
char *pchLittleEndian = (char*)ptrLittleEndian;
char *pchBigEndian = (char*)ptrBigEndian;
for ( size_t i = 0 ; i < bufLen ; i++ )
pchBigEndian[bufLen-1-i] = pchLittleEndian[i];
}
std::uint32_t row = 0x12345678;
char buf[4];
writeLittleEndianToBigEndian( &row, &buf, sizeof(row) );