什么是大端和小端?
为什么要颠倒字节存储顺序?
该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。
在编码时,您可能已通过网络发送数据或读取特定文件。 在某些情况下,得出的值与我的预期完全不同。 这种现象的正式名称是Endianness排列法。 也就是说,它们被称为 Big Endian 和 Little Endian。
CPU在内存中存储4字节int型数据时,并不是将其作为一个整体打包,而是将其分成1字节的块,并按顺序存储在各个地址中。 这时候就看你是从最大位(MSB)开始按顺序排列,还是从最小位(LSB)开始倒序排列。 数据在内存中的放置方式完全不同。
如果你按照直观的顺序放置数字,就像一个人读取它们一样,那么它们就是大端字节序,如果你以相反的顺序放置它们以便机器更容易计算它们,那么它们就是小端字节序。 大多数现代PC,例如我们主要使用的Intel或AMD CPU,都采用小端系统。
我们自己用代码来验证一下。
#include <iostream>
#include <iomanip>
int main() {
//4字节十六进制整数数据
unsigned int number = 0x12345678;
//转换指针以检查每个字节在内存中的存储方式
unsigned char* bytePtr = reinterpret_cast<unsigned char*>(&number);
for (int i = 0; i < sizeof(int); ++i) {
std::cout << "&bytePtr[" << i << "] : 0x"
<< std::hex << std::setw(2) << std::setfill('0')
<< (int)bytePtr[i] << std::endl;
}
/*
* 基于小端系统
* &bytePtr[0] : 0x78 //最小单元 (LSB) 首先进入最低地址
* &bytePtr[1] : 0x56
* &bytePtr[2] : 0x34
* &bytePtr[3] : 0x12
*
* 基于大端系统
* &bytePtr[0] : 0x12 //最大单元(MSB)首先进入最低地址。
* &bytePtr[1] : 0x34
* &bytePtr[2] : 0x56
* &bytePtr[3] : 0x78
*/
return 0;
}
这里出现一个问题。无论如何都会存储相同的值, 为什么他们采用一种不直观的倒置数据存储方法,比如小尾数法? 这是由于CPU内部加法器的设计和类型转换的效率。
当CPU对两个数进行加减运算时,必须从1的位置开始计算,即最小的位数,才能进行进位。 在小端字节序中,最小单元(LSB)位于内存中的第一个地址, CPU一读取内存,就可以立即开始执行算术运算。 此外,当向下转换以将 4 字节整数截断为 1 字节(字符)时, 硬件逻辑大大简化,因为只需要提取内存的起始地址,无需额外的地址计算。
另一方面,大端字节序对于人类在查看内存转储时读取起来很直观, 当比较两个数字的大小时,它的优点是从第一个数字开始比较。 因此,为了避免交换数据时出现混乱, 在互联网协议 (TCP/IP) 等网络标准通信中,使用大端字节序作为标准。