大端、小端基础知识
上了年纪,记性不好,用到的就记下来了
(1)大、小端序的由来(只是说一下大、小端名字的由来 摘自<深入理解计算机系统第三版>)
术语“little endian(小端)”和“big endian(大端)”出自Jonathan Swift的《格列佛游 记》(Gulliver's Trabels)一书,其中交战的两个派别无法就应该从哪一端(小端还是大端)打开一个半熟的鸡蛋达成一致。
一下是Jonathan Swift在1726年关于大小端之争历史的描述:
“......下面要告诉你的是,Lilliput和Blefuscu这两大强国在过去36个月里一直在苦战。战争开始是由于以下的原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端,可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋是碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极为反感。历史告诉我们,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。这些叛乱大多都是由Blefuscu的国王大臣们煽动起来的。叛乱平息后,流亡的人总是逃到那个帝国去寻救避难。据估计,先后几次有11000人情愿受死也不肯去打破鸡蛋较小的一端。关于这一争端,曾出版过几百本大部著作,不过大端派的书一直是受禁的,法律也规定该派的任何人不得做官。”(此段译文摘自网上蒋剑锋译的 《格列佛游记》第一卷第4章。)
在他那个时代,Swift是在讽刺英国(Lilliput)和法国(Blefuscu)之间的持续的冲突。Danny Cohen,一位网络协议的早期开创者,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了
(2)大、小端存储顺序
大端和小端实际上是字节顺序与存储地址顺序相对应的两种模式,但是不管是大端还是小端, 数据一定是从内存的低地址依次向高地址读取和写入 。
比如向内存地址为 0X1000 的地址写入 0X12345678 这个四字节16进制数,
对于 大端模式,即低地址存放高字节数:

对于小端存储,即低地址存储低字节数:

当大端模式存储的嵌入式设备向小端模式存储的PC主机发送数据,如下图所示:

嵌入式设备 A 向PC主机 B 发送数据 0X12345678 时,在A内存中,数据存储如下图所示,

依次从低地址读取数据,首先读取 0X12, 再依次读取 0X34、0X56、0X78, 经过网络传输(基于TCP/IP都是大端模式,无须转换),将先读取到的数据 0X12 以及 0X34、0X56、0X78 依次写入 B 的内存中,还是先从低地址写入,在 B 中存储如下图所示:

我们发现同一数据在A内存与B内存中存储是相同的,但是按照小端存储的规定:低地址存放低字节,高地址存放高字节将数据读取出来,数据变为 0X78563412 ,因此在大端向小端传送数据或者小端向大端传送数据时,需要进行大小端转换。
常用的字节序转换函数有:
1、htons把unsigned short类型从主机序转换到网络序(host to network short)
2、htonl把unsigned long类型从主机序转换到网络序(host to network long)
3、ntohs把unsigned short类型从网络序转换到主机序(network to host short)
4、ntohl把unsigned long类型从网络序转换到主机序(network to host long)
(3)大、小端存储各自的优势
小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
大端模式 :符号位的判定固定为第一个字节,容易判断正负
(4)如何判断大、小端序
BOOL IsBigEndian()
union NUM
int a;
char b;
}num;
num.a = 0x1234;
if( num.b == 0x12 )
return TRUE;
return FALSE;
}
根据联合体的特性判断大小端序我觉得是最简单的了(
https://www.
cnblogs.com/still-smile
/p/11595775.html
)代码摘自这个链接。
(5)64位大、小端转换
/*
* 64位小端转换为大端
long unsigned int hton_ll(long unsigned int data)
long host_h;
long host_l;
long unsigned int temp;
host_l = data & 0xffffffff;
host_h = (data >> 32) & 0xffffffff;