目录
字节序是什么意思
字节序(Byte Order)是指计算机中多字节数据类型(如整型、浮点型等)在内存中存储的顺序。
常见的字节序有两种:
- 大端序(Big-Endian):数据的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。类比于数字的书写顺序:高位在前,低位在后。
- 小端序(Little-Endian):数据的低位字节存储在内存的低地址处,高位字节存储在内存的高地址处。类比于数字的书写顺序:低位在前,高位在后。
字节序的选择对于数据的解析和传输都非常重要。如果发送方和接收方的字节序不一致,就会导致数据解析错误。因此,在进行跨平台数据交互时,需要明确指定和处理字节序,以确保数据的正确传输和解析。
注:可以在代码中采取条件编译,根据字节序的不同选择不同的成员顺序,以适应不同的字节序要求。这样可以保证在不同的平台上都能正确地解析数据。
不同字节序举例
- 大端序:
- 整数值 0x12345678 在内存中存储为:0x12 0x34 0x56 0x78(由4个字节组成的16进制序列,每个字节都用两个16进制数表示)
- 浮点数值3.14在内存中存储为:0x40 0x48 0xf5 0xc3
- 小端序:
- 整数值 0x12345678 在内存中存储为:0x78 0x56 0x34 0x12
- 浮点数值 3.14 在内存中存储为:0xc3 0xf5 0x48 0x40
注:不同的处理器架构和操作系统可能采用不同的字节序。例如,x86架构的处理器通常采用小端序,而网络协议常使用大端序。因此,在进行跨平台数据交互时,需要注意字节序的转换和处理,以确保数据的正确传输和解析。
整数字节序转换C++代码示例
使用位操作进行转换
我们定义了两个函数 bigEndianToLittleEndian16 和 bigEndianToLittleEndian32,用于将大端序的 16 位整数和 32 位整数转换为小端序。通过位操作和移位运算,我们可以将字节的顺序进行转换。
#include <iostream>
#include <cstdint>
#include <cstring>
// 将一个 16 位整数从大端序转换为小端序
uint16_t bigEndian2LittleEndian16(uint16_t value)
{
return (value >> 8) | (value << 8);
}
// 将一个 32 位整数从大端序转换为小端序
uint32_t bigEndian2LittleEndian32(uint32_t value)
{
return ((value & 0xFF000000) >> 24) | ((value & 0x00FF0000) >> 8) | ((value & 0x0000FF00) << 8) | ((value & 0x000000FF) << 24);
}
int main()
{
uint16_t bigEndian16 = 0x1234;
uint32_t bigEndian32 = 0x12345678;
uint16_t littleEndian16 = bigEndian2LittleEndian16(bigEndian16);
uint32_t littleEndian32 = bigEndian2LittleEndian32(bigEndian32);
std::cout << "Big Endian 16: 0x" << std::hex << bigEndian16 << std::endl;
std::cout << "Little Endian 16: 0x" << std::hex << littleEndian16 << std::endl;
std::cout << "Big Endian 32: 0x" << std::hex << bigEndian32 << std::endl;
std::cout << "Little Endian 32: 0x" << std::hex << littleEndian32 << std::endl;
return 0;
}
对应的小端序转为大端序的函数为:
// 将一个 16 位整数从小端序转换为大端序
uint16_t littleEndianToBigEndian16(uint16_t value) {
return (value >> 8) | (value << 8);
}
// 将一个 32 位整数从小端序转换为大端序
uint32_t littleEndianToBigEndian32(uint32_t value) {
return ((value & 0xFF000000) >> 24) | ((value & 0x00FF0000) >> 8) |
((value & 0x0000FF00) << 8) | ((value & 0x000000FF) << 24);
}
使用boost::endian
库进行转换
#include <iostream>
#include <boost/endian/conversion.hpp>
int main()
{
uint16_t bigEndian16 = 0x1234;
uint32_t bigEndian32 = 0x12345678;
uint16_t littleEndian16 = boost::endian::native_to_little(bigEndian16);
uint32_t littleEndian32 = boost::endian::native_to_little(bigEndian32);
std::cout << "Big Endian 16: 0x" << std::hex << bigEndian16 << std::endl;
std::cout << "Little Endian 16: 0x" << std::hex << littleEndian16 << std::endl;
std::cout << "Big Endian 32: 0x" << std::hex << bigEndian32 << std::endl;
std::cout << "Little Endian 32: 0x" << std::hex << littleEndian32 << std::endl;
return 0;
}
对应的小端序转为大端序的示例为:
uint16_t bigEndian16 = boost::endian::native_to_big(littleEndian16);
uint32_t bigEndian32 = boost::endian::native_to_big(littleEndian32);
使用Poco::ByteOrder
类进行转换
#include <iostream>
#include <Poco/ByteOrder.h>
int main()
{
uint16_t bigEndian16 = 0x1234;
uint32_t bigEndian32 = 0x12345678;
uint16_t littleEndian16 = Poco::ByteOrder::flipBytes(bigEndian16);
uint32_t littleEndian32 = Poco::ByteOrder::flipBytes(bigEndian32);
std::cout << "Big Endian 16: 0x" << std::hex << bigEndian16 << std::endl;
std::cout << "Little Endian 16: 0x" << std::hex << littleEndian16 << std::endl;
std::cout << "Big Endian 32: 0x" << std::hex << bigEndian32 << std::endl;
std::cout << "Little Endian 32: 0x" << std::hex << littleEndian32 << std::endl;
return 0;
}
对应的小端序转为大端序的示例为:
uint16_t bigEndian16 = Poco::ByteOrder::flipBytes(littleEndian16);
uint32_t bigEndian32 = Poco::ByteOrder::flipBytes(littleEndian32);
其他类型字节序转换
对于非整数类型(如字符串、结构体等),字节序的转换需要更加谨慎和具体情况而定。一般情况下,字符串的字节序转换需要考虑字符编码的影响。
如果你需要对字符串进行字节序转换,可以将字符串转换为字节数组,然后对字节数组进行字节序转换,最后再将字节数组转换回字符串。
字符串
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
// 将字符串转换为字节数组std::vector<uint8_t>
std::vector<uint8_t> string2Bytes(const std::string& str){
// str.begin() 返回一个迭代器,指向字符串 str 的起始位置,即第一个字符处。 str.end() 返回一个迭代器,指向字符串 str 结束位置的下一个位置,即字符串末尾之后的位置。在 C++ 中,字符串是一种容器,可以使用迭代器来遍历其中的字符。
// 使用了迭代器来遍历字符串中的每个字符,并将每个字符转换为 uint8_t 类型后添加到 std::vector<uint8_t> 容器中。
std::vector<uint8_t> bytes(str.begin(), str.end());
return bytes;
}
// 将字节数组转换为字符串
std::string bytes2String(const std::vector<uint8_t>& bytes){
std::string str(bytes.begin(), bytes.end());
return str;
}
// 对字节数组进行字节序转换
void flipBytes(std::vector<uint8_t>& bytes){
std::reverse(bytes.begin(), bytes.end());
}
int main()
{
std::string str = "Hello, World!";
// 将字符串转换为字节数组
std::vector<uint8_t> bytes = string2Bytes(str);
// 对字节数组进行字节序转换
flipBytes(bytes);
// 将字节数组转换为字符串
std::string convertedStr = bytes2String(bytes);
std::cout << "Original string: " << str << std::endl;
std::cout << "Converted string: " << convertedStr << std::endl;
return 0;
}