大端编址和小端编址

in 星海拾贝 with 0 comment

在日常使用中可能不会涉及编址方式, 但在通信中却必须了解编址的方式是大端还是小端。上次折腾的通信中刚好涉及到了这一块,于是简单总结下。

ApplicationFrameHost_5PGoJd8dMw.png

命名由来

英国作家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-->high0x1000x101
大端编址0x010x23
小端编址0x230x01

假设整数存储为4个字节(对于那些使用基于DOS的编译器,如C ++ 3.0,整数是2个字节),那么值为0x01234567的变量x将存储如下。

地址 low-->high0x1000x1010x1020x103
大端编址0x010x230x450x67
小端编址0x670x450x230x01

大小端的判断

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

参考文章

Little and Big Endian Mystery

详解大端模式和小端模式

Responses