在日常使用中可能不会涉及编址方式, 但在通信中却必须了解编址的方式是大端还是小端。上次折腾的通信中刚好涉及到了这一块,于是简单总结下。
命名由来
英国作家Jonathan Swift在1726年的《格利佛游记》中描述的关于大端和小端的争论:
Lilliput和Blefuscu陷入旷日持久的战争。战争的理由却有些奇怪,人们吃鸡蛋通常都是从敲碎比较大的一端开始。当时国王的祖父,当他还是孩子的时候,他也按照这种方式吃鸡蛋,但是却不小心划伤了手指,他的父亲因此颁布了一条法令,命令所有国民都必须从敲碎鸡蛋的较小的一端开始吃,不然就处以数额巨大的罚款。
在那个年代,Swift只是想借此来讽刺England(Lilliput)和France(Blefuscu)之间的冲突。Dnany Cohen,一个网络协议的先行者,首次运用“大端”的称谓来表示字节顺序,后来这个术语被广泛采用。
大小端定义
大端和小端是存储多字节数据类型(int,float等)的两种方式。在大端机器中,首先存储多字节数据类型的二进制表示的第一个字节;而在小端机器中,首先存储多字节数据类型的二进制表示的最后一个字节。
即有:
1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
大小端图示
假设整数存储为2个字节(short),那么值为0x0123的变量x将存储如下。
地址 low-->high | 0x100 | 0x101 |
---|---|---|
大端编址 | 0x01 | 0x23 |
小端编址 | 0x23 | 0x01 |
假设整数存储为4个字节(对于那些使用基于DOS的编译器,如C ++ 3.0,整数是2个字节),那么值为0x01234567的变量x将存储如下。
地址 low-->high | 0x100 | 0x101 | 0x102 | 0x103 |
---|---|---|---|---|
大端编址 | 0x01 | 0x23 | 0x45 | 0x67 |
小端编址 | 0x67 | 0x45 | 0x23 | 0x01 |
大小端的判断
C语言实例:
#include <stdio.h>
int main()
{
unsigned int i = 1;
char *c = (char*)&i;
if (*c)
printf("Little endian");
else
printf("Big endian");
getchar();
return 0;
}
在上面的程序中,字符指针c指向整数i。由于char指针指向大小为1字节的字符型数据,因此它将仅包含整数的第一个字节。如果机器是小端编址,整数的最低字节将被存储为1,则 c 将为1;同理,如果机器是大端编址,那么 c将为0。
运行结果:
Little endian//不同机器有所不同
大小端互相转换
转换的思路是利用位运算,将字节顺序颠倒排列。利用 “与运算” 和 “或运算” ,再配合 “移位运算” ,实现大小端的转换。
C语言实例:
#include <stdio.h>
int reverseBytes(int i) {
return (i << 24) |
((i & 0xff00) << 8) |
((i >> 8) & 0xff00) |
(i >> 24);
}
int main() {
unsigned int a = 0x01234567;
printf("%x-->%x\n",a,reverseBytes(a));
getchar();
return 0;
}
Java实例:
public static int reverseBytes(int i) {
return (i << 24) |
((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) |
(i >>> 24);
}//参考Integer.reverseBytes(int i)
输出:
1234567-->67452301
WHY 大小端
这是因为在计算机系统中,是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
大小端哪个好
就像鸡蛋问题一样,编址方式的选择并没有强制要求,只要选择并遵守其中一个惯例,选择就是任意的。
二者各自的优点如下:
小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
大端模式 :符号位的判定固定为第一个字节,容易判断正负。
常见的字节序
一般操作系统都是小端编址,Java和所有的网络通讯协议都是使用大端编址的编码。部分游戏自定义通信协议可能采用小端编址,如之前折腾的seer2通信协议,里面使用的就是小端编址。
1.常见CPU的字节序:
Big Endian : PowerPC、IBM、Sun
Little Endian : x86、DEC
ARM既可以工作在大端模式,也可以工作在小端模式。
2.常见文件的字节序:
Adobe PS – Big Endian
BMP – Little Endian
DXF(AutoCAD) – Variable
GIF – Little Endian
JPEG – Big Endian
MacPaint – Big Endian
RTF – Little Endian
参考文章
本文由 ukuq 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Aug 3, 2019 at 11:22 pm