如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
当前回答
我喜欢这个,只是为了风格:-)
long swap(long i) {
char *c = (char *) &i;
return * (long *) (char[]) {c[3], c[2], c[1], c[0] };
}
其他回答
在大多数POSIX系统中(虽然不是在POSIX标准中)有end .h,它可以用来确定系统使用的编码。然后是这样的:
unsigned int change_endian(unsigned int x)
{
unsigned char *ptr = (unsigned char *)&x;
return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
}
这将交换顺序(从大端序到小端序):
如果你有数字0xDEADBEEF(在一个小端序系统中存储为0xEFBEADDE), ptr[0]将是0xEF, ptr[1]是0xBE,等等。
但是如果你想将它用于网络,那么htons, htonl和htonll(以及它们的逆ntohs, ntohl和ntohll)将有助于从主机顺序转换到网络顺序。
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) );
如果您这样做是为了在不同平台之间传输数据,请查看ntoh和hton函数。
认真……我不明白为什么所有的解决方案都那么复杂!最简单、最通用的模板函数如何?它可以在任何操作系统的任何情况下交换任何大小的任何类型????
template <typename T>
void SwapEnd(T& var)
{
static_assert(std::is_pod<T>::value, "Type must be POD type for safety");
std::array<char, sizeof(T)> varArray;
std::memcpy(varArray.data(), &var, sizeof(T));
for(int i = 0; i < static_cast<int>(sizeof(var)/2); i++)
std::swap(varArray[sizeof(var) - 1 - i],varArray[i]);
std::memcpy(&var, varArray.data(), sizeof(T));
}
这是C和c++结合的神奇力量!只需逐个字符交换原始变量。
要点1:没有操作符:请记住,我没有使用简单的赋值操作符“=”,因为当反转字节序时,一些对象将被打乱,复制构造函数(或赋值操作符)将不起作用。因此,一个字符一个字符地复制它们更加可靠。
Point 2: Be aware of alignment issues: Notice that we're copying to and from an array, which is the right thing to do because the C++ compiler doesn't guarantee that we can access unaligned memory (this answer was updated from its original form for this). For example, if you allocate uint64_t, your compiler cannot guarantee that you can access the 3rd byte of that as a uint8_t. Therefore, the right thing to do is to copy this to a char array, swap it, then copy it back (so no reinterpret_cast). Notice that compilers are mostly smart enough to convert what you did back to a reinterpret_cast if they're capable of accessing individual bytes regardless of alignment.
使用此函数:
double x = 5;
SwapEnd(x);
现在x的字节序不同了。
有一个叫做BSWAP的汇编指令可以帮你做交换,非常快。 你可以在这里阅读。
Visual Studio,或者更准确地说是Visual c++运行时库,为此提供了平台intrinsic,称为_byteswap_ushort()、_byteswap_ulong()和_byteswap_int64()。其他平台应该也有类似的情况,但我不知道它们会被称为什么。