CPU的大小端模式是指在存储和处理多字节数据时,字节的顺序是如何排列的。它涉及到字节在内存中的存储方式以及读取和解释这些字节的顺序。主要有两种大小端模式:大端模式(Big-Endian)和小端模式(Little-Endian)。
大端模式(Big-Endian)
在大端模式下,数据的高位字节存储在低地址,低位字节存储在高地址。例如,对于十六进制数0x12345678,在大端模式下,其在内存中的存储顺序为12 34
56 78。这种存储方式符合人类的直观认知,适合需要人类直接读取和处理数据的场景12。
小端模式(Little-Endian)
与大端模式相反,小端模式下数据的低位字节存储在低地址,高位字节存储在高地址。例如,对于十六进制数0x12345678,在小端模式下,其在内存中的存储顺序为78
56 34 12。小端模式在计算机系统中更为常见,因为它使得数据的读取和写入更加高效12。
大小端模式的优缺点
大端模式的优点:
判断正负性非常容易,因为高位字节表示符号位。
大端模式的缺点:
数据读取顺序与人类阅读习惯相反,可能导致效率较低。
小端模式的优点:
数据读取顺序与人类阅读习惯一致,读取和写入效率较高。
小端模式的缺点:
判断正负性需要更多的计算步骤。
不同体系结构的大小端模式
不同的体系结构有不同的默认模式:
x86架构:通常采用小端模式。
网络协议:常用的网络字节序采用大端模式(例如TCP/IP协议)。
为什么会有大小端模式之分呢?
因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。
但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的int型。另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。
对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。
一、大小端存储机制
1.大端模式(Big-Endian)
大端模式,也被称为大字节序。在这种模式下,数据的高位字节存储在低地址,低位字节存储在高地址。这就好比我们人类书写数字的习惯,从左到右,高位在前,低位在后。例如,对于一个十六进制数
0x12345678,它由4个字节组成,分别是 0x12、0x34、0x56 和 0x78。在大端模式下,存储顺序为 0x12 0x34 0x56
0x78。从内存地址的角度来看,低地址处存储的是高位字节 0x12,随着地址的升高,依次存储 0x34、0x56 和
0x78。这种存储方式符合人类的直观认知,在一些需要人类直接读取和处理数据的场景中具有一定的优势。
为了更好地理解大端模式,我们可以想象一个书架,每一层代表一个内存地址,而书本则代表字节数据。当我们按照大端模式摆放书本时,会将重要的信息(高位字节)放在书架的底层(低地址),随着层数的增加,依次放置次要的信息(低位字节)。这样,当我们从书架底部开始读取书本时,就能按照我们习惯的顺序获取数据。
大小端(Endianess)是指计算机系统在存储多字节数据时,字节的顺序,即存储数据的字节顺序。
计算机系统的内存是以字节为单位进行划分的,每个地址单元都对应着一个字节,一个字节的大小为8bit,可以存放一个8位的二进制数,比如10101010。但是在C语言中除了8bit的char类型之外还有16bit的short类型,32bit的long类型,这主要取决于具体的编译器。且对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于1个字节,那么必然存在着如何将多个字节安排进入内存的问题,因为就产生的大端存储模式和小端存储模式。
2.小端模式(Little-Endian)
与大端模式相反,小端模式(Little-Endian)下,数据的低位字节存储在低地址,高位字节存储在高地址。同样以 0x12345678
为例,在小端模式下,存储顺序为 0x78 0x56 0x34 0x12。这意味着在低地址处存储的是低位字节 0x78,而高位字节 0x12
则存储在高地址处。小端模式在x86/ARM等常见的处理器架构中被广泛使用。
我们依然以书架为例来理解小端模式。在小端模式下,我们会将不太重要的信息(低位字节)放在书架的底层(低地址),而重要的信息(高位字节)则放在书架的上层(高地址)。这种存储方式虽然与人类的书写习惯不同,但在计算机的处理过程中却有着独特的优势。例如,在进行数据的加法、减法等运算时,小端模式可以更方便地处理低位字节,提高运算效率。
二、数据传输中的大小端问题
当一台小端机器需要向网络发送数据时,它必须先将数据从本机的小端模式转换为大端模式。这是因为网络协议规定了数据在网络中传输时必须采用大端模式,只有这样,接收方才能正确地解析数据。例如,一台采用x86架构的计算机(小端模式)要向另一台计算机发送一个32位的整数
0x12345678,在发送之前,它需要将这个数据转换为大端模式 0x12 0x34 0x56 0x78 再进行发送。
在接收数据时,小端机器又需要将接收到的大端模式数据转换回小端模式,以便在本机上进行正确的处理。例如,当这台x86计算机接收到一个来自网络的32位整数数据时,它会先将数据从大端模式转换为小端模式,然后再进行后续的处理。这个转换过程就像是一场翻译工作,确保数据在不同的“语言环境”(端模式)之间能够正确地交流。
网络协议强制使用大端字节序的原因主要是为了保证数据的一致性和兼容性。不同的计算机可能采用不同的端模式,如果没有统一的标准,数据在传输过程中就会出现混乱。例如,一个小端机器发送的数据在另一个大端机器上可能会被错误地解析,导致数据的错误处理。通过统一采用大端字节序,网络协议为不同端模式的计算机之间搭建了一座沟通的桥梁,使得数据能够在网络中准确地传输和共享。
大小端的转换
在处理数据时,尤其是在网络通信和文件读写中,可能需要在大端(Big Endian)和小端(Little
Endian)之间进行转换。以下是几种常见的大小端转换方法,包括使用标准库函数和手动实现。
使用标准库函数
在许多C标准库中,提供了网络字节序的转换函数,可以用来进行大小端的转换。以下是几个常用的函数:
htonl():将主机字节顺序转换为网络字节顺序(32位整数)
htons():将主机字节顺序转换为网络字节顺序(16位整数)
ntohl():将网络字节顺序转换为主机字节顺序(32位整数)
ntohs():将网络字节顺序转换为主机字节顺序(16位整数)