计算机大端和小端详解(BigEndian&LittleEndian)

来源:互联网 发布:windows正版验证 编辑:程序博客网 时间:2024/04/28 06:38

大端模式和小端模式的起源

关于大端小端名词的由来 , 有一个有趣的故事 , 来自于 Jonathan Swift的 [格利佛游记] , Lilliput 和 Blefuscu 这两个强国在过去的 36 个月中一直在苦战 , 战争的原因 : 大家都知道 , 吃鸡蛋的时候 , 原始的方法是打破鸡蛋较大的一端 , 可那时的皇帝的祖父由于小时侯吃鸡蛋 , 按这种方法把手指弄破了 , 因此他的父亲 , 就下令 , 命令所有的子民吃鸡蛋的时候 , 必须先打破鸡蛋较小的一端 , 违令者重罚 ; 然后老百姓对此法令极为反感 , 期间发生了多次叛乱 , 其中一个皇帝因此送命 , 另一个丢了王位 , 产生叛乱的原因就是另一个国家 Blefuscu 的国王大臣煽动起来的 , 叛乱平息后 , 就逃到这个帝国避难 ; 据估计 , 先后几次有 11000 余人情愿死也不肯去打破鸡蛋较小的端吃鸡蛋 ; 这个其实讽刺当时英国和法国之间持续的冲突 ; Danny Cohen 一位网络协议的开创者 , 第一次使用这两个术语指代字节顺序 , 后来就被大家广泛接受 ;

大端和小端原理

对于整型 , 长整型等数据类型 , BigEndian 认为第一个字节是最高位字节 (按照从低地址到高地址的顺序存放数据的高位字节到低位字节) ;

而 LittleEndian 则相反 , 它认为第一个字节是最低位字节 (按照从低地址到高地址的顺序存放据的低位字节到高位字节) ;

例如 , 假设从内存地址 0x0000 开始有以下数据 :

0x0000      0x0001      0x0002      0x00030x12          0x34          0xab          0xcd

如果我们去读取一个地址为 0x0000 的四个字节变量 , 若字节序为 BigEndian , 则读出结果为 0x1234abcd , 若字节序为 LittleEndian , 则读出结果为 0xcdab3412 ;

如果我们将 0x1234abcd 写入到以 0x0000 开始的内存中 , 则 LittleEndian 和 BigEndian 模式的存放结果如下 :

Addr                  0x0000          0x0001       0x0002          0x0003 BigEndian          0x12              0x34           0xab               0xcd  LittleEndian        0xcd              0xab           0x34               0x12

一般来说 , x86 系列 CPU 都是 LittleEndian 的字节序 , PowerPC 通常是 BigEndian , 网络字节顺序也是 BigEndian 还有的CPU 能通过跳线来设置 CPU 工作于 LittleEndian 还是 BigEndian 模式 ;

对于0x12345678的存储:

小端模式:(从低字节到高字节)
低位地址 0x78 0x56 0x34 0x12 高位地址

大端模式:(从高字节到低字节)
低位地址 0x12 0x34 0x56 0x78 高位地址

大端小端检测方法

int i = 1;   char *p = (char *)&i;   if(*p == 1){    printf("Little Endian");}else{    printf("Big Endian");}

实现同样的功能 , 来看看 Linux 操作系统中相关的源代码是怎么做的 :

static union { char c[4]; unsigned long mylong; } endian_test = {{ 'l', '?', '?', 'b' } };#define ENDIANNESS ((char)endian_test.mylong)

Linux 的内核作者们仅仅用一个 union 变量和一个简单的宏定义就实现了一大段代码同样的功能 (如果 ENDIANNESS=’l’ 表示系统为 LittleEndian , 为 ’b’ 表示 BigEndian)

作者 Github : tojohnonly , 博客 : EnskDeCode