【协议森林】详解大端(big endian)与小端(little endian)
1、字节序
字节顺序,又称端序或尾序(英语:Endianness)。在几乎所有的机器上,多字节对象都被存储为连续的字节序列。例如在C语言中,一个类型为int的变量x地址为0x100,那么其对应地址表达式&x的值为0x100。且x的四个字节将被存储在存储器的0x100, 0x101, 0x102, 0x103位置,这就是所谓的字节序。字节存放的顺序有两种模式:大端模式和小端模式。
2、大小端由来
在乔纳森·斯威夫特的著名讽刺小说《格列夫游记》中,小人国内部分裂成Big-endian和Little-endian两派,区别在于一派要求从鸡蛋的大头把鸡蛋打破,另一派要求从鸡蛋的小头把鸡蛋打破。斯威夫特借以讽刺英国的政党之争,在计算机工业中指数据储存顺序的分歧。
3、大小端模式定义
大端模式(big endian):数据的高位字节保存在内存的低地址中,而低位字节保存在内存的高地址中。
小端模式(little endian):数据的高位字节保存在内存的高地址中,而低位字节保存在内存的低地址中。
举一例说明,高位字节和低位字节其实和我们平时所用的十进制数的个十百千万类似,例如3521,则3在最高位(千位),其次是5(百位),接着是2(十位),最后是1(各位)。
在裘宗燕翻译的《程序设计实践》里,这对术语并没有翻译为“大端”和小端,而是**“高尾端”和“低尾端”**,这就好理解了:如果把一个数看成一个字符串,比如11223344看成"11223344",末尾是个’\0’,'11’到’44’个占用一个存储单元,那么它的尾端很显然是44,前面的高还是低就表示尾端放在高地址还是低地址,它在内存中的放法非常直观,如下图:
4、如何判断大小端
我们可以依照两种字节序的存储特性来判断,代码如下:
#include<stdio.h>
int main()
{
int x =1;
if(*(char *)&x == 1) //取x的地址,强转为单字节char后解引用
printf(It's little endian!\n); //小端模式
else
printf("It's big endian!\n"); //大端模式
return 0;
}
其主要原理是获取 x 的最低字节,为0x00,说明是大端;为0x01,说明是小端。
若是大端,则整形数字1应该这样存储:
若是小端,则整形数字1应该这样存储:
5、网络字节序
网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确地解释。
所有的网络协议都是采用大端(big endian)方式来传输数据的,因此,有时也将big endian方式称为网络字节序。
htons:将unsigned short类型从主机字节序转换到网络字节序。
htonl:将unsigned long类型从主机字节序转换到网络字节序。
ntohs:将unsigned short类型从网络字节序转换到主机字节序。
ntohl:将unsigned long类型从网络字节序转换到主机字节序。
注:在使用little endiand的机器中,这些函数会按照对应的规则进行转换;在使用big endian的机器中,这些函数会成为空宏。