大端(Big Endian)和小端(Little Endian)是一种描述计算机存储多字节数据的方式。
想象一下,你有一串数字,例如1234,这个数字需要用两个字节(或更多)来存储。那么问题是,这个数字的哪个部分先存储在内存的起始位置(低地址),哪个部分先存储在内存的结束位置(高地址)
不同的计算机架构使用不同的字节序,没有统一的标准。通常,x86架构(包括大多数个人电脑和服务器)使用小端字节序,而一些其他架构如PowerPC和SPARC使用大端字节序。因此,当你在处理二进制数据或者与其他系统进行数据交互时,需要注意字节序的差异,以确保数据被正确解释和处理。这也是为什么在网络通信中会有网络字节序(通常是大端)和主机字节序(取决于计算机架构)之间的转换
大端(Big Endian)和小端(Little Endian)是两种不同的内存存储格式,它们定义了多字节数据(如整数、浮点数等)在内存中的排列方式。理解这两种格式对于编程和系统设计非常重要,特别是在涉及到网络通信和跨平台数据交换时。
大端模式(Big Endian)
在大端模式下,数据的"大端"(即最高有效字节)存储在内存的低地址端,而数据的"小端"(即最低有效字节)存储在内存的高地址端。这意味着,比如一个32位的整数0x12345678,在内存中的存储顺序(从低地址到高地址)将是:
0x12 0x34 0x56 0x78
小端模式(Little Endian)
相反,在小端模式下,数据的"小端"(即最低有效字节)存储在内存的低地址端,而数据的"大端"(即最高有效字节)存储在内存的高地址端。同样的32位整数0x12345678,在内存中的存储顺序将是:
0x78 0x56 0x34 0x12
在这个图表中,我们展示了一个32位整数(0x12345678)在大端和小端模式下的内存布局。每个方框代表一个字节的内存位置,箭头表示地址的增加方向。从图表中可以清晰地看出,大端模式将最高有效字节放在最低的内存地址处,而小端模式则相反,将最低有效字节放在最低的内存地址处。
通过这样的图表,可以直观地理解大端和小端模式的不同,以及它们在内存中是如何存储数据的。
// 大端转小端
uint16_t bigEndianValue = 0x1234;
uint16_t littleEndianValue;
memcpy(&littleEndianValue, &bigEndianValue, sizeof(uint16_t));
// 小端转大端
uint16_t littleEndianValue = 0x3412;
uint16_t bigEndianValue;
memcpy(&bigEndianValue, &littleEndianValue, sizeof(uint16_t));
uint16_t bigEndianValue = 0x1234;
uint16_t littleEndianValue = BIG_ENDIAN_TO_LITTLE_ENDIAN_16(bigEndianValue);
uint32_t anotherBigEndianValue = 0x12345678;
uint32_t anotherLittleEndianValue = BIG_ENDIAN_TO_LITTLE_ENDIAN_32(anotherBigEndianValue);
#include
uint16_t bigEndianValue = 0x1234;
uint16_t littleEndianValue = boost::endian::endian_reverse(bigEndianValue);
#include
#include
int main() {
if (std::endian::native == std::endian::big) {
std::cout << "This system uses big endian." << std::endl;
} else if (std::endian::native == std::endian::little) {
std::cout << "This system uses little endian." << std::endl;
} else {
std::cout << "Unknown endian." << std::endl;
}
return 0;
}
#include
#include
#include
//1字节对齐
#pragma pack(push, 1)
struct MyStruct {
uint16_t a;
uint32_t b;
uint16_t c;
};
#pragma pack(pop)
MyStruct bigToLittleEndian(const MyStruct& bigEndianValue) {
MyStruct littleEndianValue;
std::memcpy(&littleEndianValue, &bigEndianValue, sizeof(MyStruct));
return littleEndianValue;
}
MyStruct littleToBigEndian(const MyStruct& littleEndianValue) {
return bigToLittleEndian(littleEndianValue);
}
int main() {
MyStruct bigEndianValue = {0x1234, 0x56789ABC, 0x5678};
MyStruct littleEndianValue = bigToLittleEndian(bigEndianValue);
std::cout << "Big Endian Value: " << std::hex << bigEndianValue.a << " " << bigEndianValue.b << " " << bigEndianValue.c << std::endl;
std::cout << "Little Endian Value: " << std::hex << littleEndianValue.a << " " << littleEndianValue.b << " " << littleEndianValue.c << std::endl;
return 0;
}
#include
#include
// 大端转小端
QByteArray bigToLittleEndian(const QByteArray &bigEndianData) {
QByteArray littleEndianData(bigEndianData);
for (int i = 0; i < littleEndianData.size(); i++) {
littleEndianData[i] = bigEndianData.at(littleEndianData.size() - 1 - i);
}
return littleEndianData;
}
// 小端转大端
QByteArray littleToBigEndian(const QByteArray &littleEndianData) {
QByteArray bigEndianData(littleEndianData);
for (int i = 0; i < bigEndianData.size(); i++) {
bigEndianData[i] = littleEndianData.at(bigEndianData.size() - 1 - i);
}
return bigEndianData;
}
int main() {
uint16_t bigEndianValue = 0x1234;
QByteArray bigEndianData(reinterpret_cast(&bigEndianValue), sizeof(uint16_t));
QByteArray littleEndianData = bigToLittleEndian(bigEndianData);
QByteArray backToBigEndian = littleToBigEndian(littleEndianData);
// 输出结果
qDebug() << "Big Endian Data:" << bigEndianData.toHex();
qDebug() << "Little Endian Data:" << littleEndianData.toHex();
qDebug() << "Back to Big Endian Data:" << backToBigEndian.toHex();
return 0;
}
QDataStream stream(&byteArray, QIODevice::ReadWrite);
stream.setByteOrder(QDataStream::LittleEndian); // 设置为小端
quint16 value;
stream >> value; // 从小端数据中读取16位无符号整数
quint16 bigEndianValue = 0x1234;
QByteArray byteArray = QByteArray(reinterpret_cast(&bigEndianValue), sizeof(quint16));
quint16 littleEndianValue = qFromBigEndian(byteArray.constData());
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
// 当前系统是小端
} else {
// 当前系统是大端
}
quint16 littleEndianValue = 0x1234;
quint16 nativeValue = qFromLittleEndian(littleEndianValue); // 转换为本机字节顺序
quint16 nativeValue = 0x1234;
quint16 littleEndianValue = qToLittleEndian(nativeValue); // 转换为小端表示