大端模式和小端模式

大端:低地址存高位(高地址存低位)windows

小端:低地址存低位(高地址存高位)网络

 

1.故事的起源 架构

  “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开仍是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另外一个丢了王位。 函数

咱们通常将endian翻译成字节序,将big endianlittle endian称做大尾小尾spa

 

2.什么是Big Endian和Little Endian? 操作系统

在设计计算机系统的时候,有两种处理内存中数据的方法。一种叫为little-endian,存放在内存中最低位的数值是来自数据的最右边部分(也就是数据的最低位部分)。 好比某些文件须要在不一样平台处理,或者经过Socket通讯。这方面咱们能够借助ntohl(), ntohs(), htonl(), and htons()函数进行格式转换, 翻译

我的补充:一个操做数做htonlntohl结果不必定相同,当机器字节序跟网络字节序恰好是仅仅big endianlittle endian的区别时是相同的。 设计

 

3. 如何理解Big Endian和Little Endian  指针

举个例子:内存

int a = 1;

a这个数自己的16进制表示是0x00 00 00 01

在内存中怎么存储呢?

若是你的CPUintel x86架构的(基本上就是一般咱们说的奔腾cpu),那么就是0x01 0x00 0x00 0x00 , 这也就是所谓的little-endian, 低字节存放在内存的低位.

若是你的CPU是老式AMD系列的(很老很老的那种,由于最新的AMD系列已是x86架构了), 它的字节序就是big-endian, 其内存存储就是 0x00 0x00 0x00 0x01在内存中从高字节开始存放。

如今世界上绝大多数的CPU都是little-endian

 

4. 了解big-endian和little-endian有什么做用?

一个重要的做用就是了解在网络上不一样的机器间的数据如何传输。 假设咱们在网络上有两台机器AB, 其中Alittle-endian,Bbig-endian 机器A要传输上面的整数a给机器B,如何传输呢? 过程是这样的:

机器A先把a在内存中的四个字节0x 01 0x00 0x00 0x00转化为网络字节序0x00 0x00 0x00 0x01,而后一个字节一个字节(0x000x01)喂到网络上去 ,而后机器B从网络上一个字节一个字节地取出四个字节0x00 0x00 0x00 0x01后又会转化为本地字节序 0x00 0x00 0x00 0x01后放入内存。于是B正确地获得了来自A的数据a 。若是数据缺乏在网络上的字节序转换的话,状况会怎样呢?

机器A先把a由在内存的四个字节0x 01 0x00 0x00 0x00 一个字节一个字节地喂到网络上,而后机器B从网络上一个字节一个字节地收到0x 01 0x00 0x00 0x00并放入到内存中, B认为他收到了0x01000000, 也就是十进制数1677216,这显然是错误的.

 

5.如何判断系统是Big Endian仍是Little Endian

/usr/include/中(包括子目录)查找字符串BYTE_ORDER(_BYTE_ORDER, __BYTE_ORDER),肯定其值。这个值通常在endian.hmachine/endian.h文件中能够找到,有时在feature.h中,不一样的操做系统可能有所不一样。通常来讲,Little Endian系统BYTE_ORDER(_BYTE_ORDER,__BYTE_ORDER)1234Big Endian系统为4321。大部分用户的操做系统(如windows, FreeBsd,Linux)是Little Endian的。少部分,如MAC OS ,Big Endian 的。本质上说,Little Endian仍是Big Endian与操做系统和芯片类型都有关系。

 

 

ARM体系中,每一个字单元包含4个字节单元或者两个半字单元。在字单元中,4个字节哪个是高位字节,哪个是低位字节则有两种不一样的格式:big-endianlittle-endian格式。在小端模式中,低位字节放在低地址,高位字节放在高地址;在大端模式中,低位字节放在高地址,高位字节放在低地址。

 

   若是将一个32位的整数0x12345678(如用UltraEdit打开某个文件看到的第一行头四个字节是:"00000000h:12 34 56 78")存放到一个整型变量(int)中,这个整型变量(文件内容)采用大端或者小端模式在内存中的存储由下表所示。

地址偏移

大端模式

小端模式

0x00

12

78

0x01

34

56

0x02

56

34

0x03

78

12

 

对于文件内容 0x12345678,把前面("12")的看为高端字节,后面("78")的看为低端字节,那么可使用"高高低低"(Little Endian),"高低高低"(Big Endian)的口诀。直观的区分,若是发现内存的内容和文件的内容在顺序上以4个字节颠倒,那么他就是Little Edian。实现Big Endian和Little Endian主要是由编译器指定的,一般是在CCFLAG 加参数,如: -DENDIAN_LITTLE,设定编译为小端字节。实际中用Trace 32能够用Memory Dump查看内存内容,和写入文件比较后判断为大端仍是小端。

 

  若是将一个16位的整数0x1234存放到一个短整型变量(short)中。这个短整型变量在内存中的存储在大小端模式由下表所示。

地址偏移

大端模式

小端模式

0x00

12

34

0x01

34

12

由上表所知,采用大小模式对数据进行存放的主要区别在于在存放的字节顺序,大端方式将高位存放在低地址,小端方式将低位存放在低地址。

  那么该如何判断CPU是大端模式仍是小端模式呢??

  在C语言中,联合体union的存放顺序是全部成员都从低地址开始存放的。利用这一特色,能够用联合体变量判断ARM或x86环境下,存储系统是是大端仍是小端模式。

  具体的代码以下:

#include "stdio.h"

int main()

{

    union w

   {

      int a;  //4 bytes

      char b; //1 byte

   } c;

    c.a=1;

    if (c.b==1)

      printf("It is Little_endian!\n");

    else

      printf("It is Big_endian!\n");

    return 1;

}

 

 

数据在存放到内存里的时候,有两种存放方式,即:Big Endian 和 Little Endian,这两个存取方式决定了内存存放数据的原则是 高高低低 原则 仍是 高低低高 原则。

高高低低--内存中的高位存放数据的高位,内存中的低位存放数据的低位(Little Endian )

高低低高--内存中的高位存放数据的低位,内存中的低位存放数据的高位(Big Endian )

好比:我有一个数据,是0xA5A1,它在存放到内存中是怎样存放的呢?由于在咱们平时的书写中,A5是高位,A1在低位,存放到内存中的时候,A1存放在0x4000这个位置,而A5存放在0x4001这个位置,高位存放在内存的高地址中,低位存放在低地址中,这种方式就是Little Endian 。

 

下面再粘一篇网友的总结的文章来详细阐述一下这两种方式的区别:

                  Big Endian  和 Little Endian 模式的区别(转载)

谈到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢?

其实big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。

    用文字说明可能比较抽象,下面用图像加以说明。好比数字0x12345678在两种不一样字节序CPU中的存储顺序以下所示:

Big Endian

   低地址                                            高地址

 ----------------------------------------------------------------------------->

   |     12     |      34    |     56      |     78    |

Little Endian 

   低地址                                            高地址

   ----------------------------------------------------------------------------->

   |     78     |      56    |     34      |     12    |

     从上面两图能够看出,采用big endian方式存储数据是符合咱们人类的思惟习惯的。

     为何要注意字节序的问题呢?你可能这么问。固然,若是你写的程序只在单机环境下面运行,而且不和别人的程序打交道,那么你彻底能够忽略字节序的存在。可是,若是你的程序要跟别人的程序产生交互呢?尤为是当你把你在微机上运算的结果运用到计算机群上去的话。

 

在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则惟一采用big endian方式来存储数据。试想,若是你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的0x12345678来讲,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,因为JAVA采起big endian方式存储数据,很天然的它会将你的数据翻译为0x78563412。所以,在你的C程序传给JAVA程序以前有必要进行字节序的转换工做。

 

全部网络协议也都是采用big endian的方式来传输数据的。因此有时咱们也会把big endian方式称之为网络字节序。当两台采用不一样字节序的主机通讯时,在发送数据以前都必须通过字节序的转换成为网络字节序后再进行传输。ANSI C中提供了下面四个转换字节序的宏。

 

一道C语言的试题:请写一个C函数,若处理器是Big_endian的,则返回0;如果Little_endian的,则返回1。

解答:

int checkCPU()

{

 {

  union w

  {

   int a;

   char b;

  } c;

  c.a = 1;

  return (c.b == 1);

 }

}

嵌入式系统开发者应该对Little-endian和Big-endian模式很是了解。采用Little-endian模式的CPU对操做数的存放方式是从低字节到高字节,而Big-endian模式对操做数的存放方式是从高字节到低字节。例如,16bit宽的数0x1234在Little- endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址 

存放内容 

0x4000

0x34

0x400 

0x12

  而在Big-endian模式CPU内存中的存放方式则为:

 

内存地址

存放内容

0x4000

0x12

0x4001

0x34

 

  32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为: 

内存地址

存放内容

0x4000

0x78

0x4001

0x56

0x4002

0x34

0x4003

0x12

 

  而在Big-endian模式CPU内存中的存放方式则为:

内存地址

存放内容

0x4000

0x12

0x4001

0x34

0x4002

0x56

0x4003

0x78

 

  联合体union的存放顺序是全部成员都从低地址开始存放,解答利用该特性,轻松地得到了CPU对内存采用Little-endian仍是Big-endian模式读写。

相关文章
相关标签/搜索