当前位置:必发365电子游戏 > 操作系统 > 从他们的存储方式可以看出
从他们的存储方式可以看出
2019-12-19

必发365电子游戏,int i=1;  

大小端方式,端形式

大小端难点关键涉嫌的是是非非单字节非字符串外的别的数据的意味和传递,如short型、int型等。大端和小端有其各自的优势。大家知道计算机符合规律的内部存款和储蓄器增加情势是从低到高(当然栈不是卡塔尔(英语:State of Qatar),取多少情势是从基址依照偏移找到他们的岗位,从她们的存款和储蓄情势得以见见,大端存款和储蓄因为第叁个字节正是高位,进而十分轻松知 道它是正数依旧负数,对于一些数值推断会相当的高效。而小端存储第三个字节是它的不及,符号位在最后三个字节,那样在做数值四则运算时从未有每趟收取相应字节运算,最后直到高位,并且最后把符号位刷新,那样的运算方式会更急迅。

short 恐怕 long的数目在举行通信的时候最棒养成:
1、发送的时候利用:htons(l)
2、接收的时候利用:ntohs(l)
而毫无理睬两侧的通讯是不是须要如此做~~
理所必然了貌似自个儿都无须int型的数码通讯,一向都以字符串通信,发送方利用sprintf组织,选拔方利用atoi进行转变~~

 

在 种种Computer体系布局中,对于字节、字等的囤积机制有所分化,因此引发了Computer通讯领 域中七个很器重的标题,即通讯双方调换的新闻单元(比特、字节、字、双字等等)应该以什么的意气风发生机勃勃举办传递。假使不达到风姿罗曼蒂克致的准绳,通讯双方将无法实行正确的编/译码进而造成通讯失利。方今在各类系统的微管理机中不足为奇选取的字节存储机制主要有二种:Big-Endian和Little-Endian,下边先 从字节序谈起。
意气风发、什么是字节序
字节序,望文生义字节的次第,再多说两句正是超过三个字节类型的数码在内部存款和储蓄器中的寄存顺序(叁个字节的多少当然就无需谈顺序的主题材料了卡塔尔(英语:State of Qatar)。其实大多数人在骨子里的开辟中都超级少会向来和字节序打交道。只有在跨平台以致互连网程序中字节序才是贰个应当被考虑的题目。

在具备的牵线字节序的文章中都会涉及字 节序分为两类:Big-Endian和Little-Endian,引用标准的Big-Endian和Little-Endian的定义如下:
a卡塔尔国Little-Endian正是低位字节排泄在内部存款和储蓄器的洼地址端,高位字节排泄在内存的高地址端。
b)Big-Endian正是高位字节排泄在内部存款和储蓄器的洼地址端,低位字节排泄在内部存款和储蓄器的高地址端。
c卡塔尔国网络字节序:TCP/IP各层协商将字节序定义为Big-Endian,由此TCP/IP左券中使用的字节序平日称得上网络字节序。

1.1 什么是高/低地址端
首先我们要清楚C程序印象中内部存款和储蓄器的半空中构造景况:在《C专家编制程序》中照旧《Unix情形高端编制程序》中有至于内部存款和储蓄器空间构造意况的证实,大约如下图:
----------------------- 最高内部存款和储蓄器地址 0xffffffff
栈底

char *p=(char *)&i;       if(*p==1)                printf("1");      else            printf("2");

栈顶

          大小端存款和储蓄难点,假如小端格局中(i占起码多个字节的长短)则i所分配的内部存款和储蓄器最小地址那些字节中就存着1,别的字节是0.大端的话则1在i的最高地址字节处寄放,char是三个字节,所以强制将char型量p指向i则p指向的终将是i的最低地址,那么就足以推断p中的值是否1来规定是还是不是小端。

NULL (空洞)

 

未先河 化的数量
----------------------- 统称数据段

请写叁个C函数,若微电脑是Big_endian的,则返回0;若是Little_endian的,则返回1

起始化的数额

正 文段(代码段)
----------------------- 最低内部存款和储蓄器地址 0x00000000
由图能够看来,再内存布满中,栈是向下抓牢的,而堆是升高拉长的。
以上海体育地方为比如果咱们在栈 上分红一个unsigned char buf[4],那么那一个数组变量在栈上是何许布局的呢?看下图:

解答:

栈底 (高地址)

**buf[3]
buf[2]
buf[1]

int checkCPU( )

buf[0]**

栈顶 (低地址)
骨子里,大家得以本人在编写翻译器里面创造一个数组,然后分别输出数组种各种成分之处,来验证一下。
1.2 什么是高/低字节
当今大家弄清了高/低地址,接着思索高/低字节。某个文章中称未有字节为最低有效位,高位字节为最高有效位。假设我们有四个34人无符号整型0x12345678,那么高位是什么样,低位又是如何呢? 其实很简短。在十进制中大家都在说靠左侧的是高位,靠右侧的是未有,在其他进制也是这么。就拿 0x12345678的话,从高位到没有的字节依次是0x12、0x34、0x56和0x78。
高/低地址端和高/低字节都弄清了。我们再来回顾一下Big-Endian和Little-Endian的概念,并用图示表达二种字节序:
以unsigned int value = 0x12345678为例,分别造访在三种字节序下其积存景况,大家能够用unsigned char buf[4]来表示value:
Big-Endian: 低地址贮存高位,如下图:

{

栈底 (高地址)

buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)

    {

buf[0] (0x12) -- 高位

栈顶 (低地址)

Little-Endian: 低地址存放低位,如下图:

           union w

栈底 (高地址)

buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)

           { 

buf[0] (0x78) -- 低位

栈 顶 (低地址)

二、各种Endian
2.1 Big-Endian
微处理机种类构造中生龙活虎种描述多字节存款和储蓄顺序的术语,在这里种机制中最要紧字节(MSB)贮存在最低级的地址 上。采取这种机制的电脑有IBM3700种类、PDP-10、Mortolora微Computer连串和超越十分之五的TiggoISC微处理机。
+----------+
| 0x34 |<-- 0x00000021
+----------+
| 0x12 |<-- 0x00000020
+----------+
图 1:双字节数0x1234以Big-Endian的办法存在最早地址0x00000020中

在Big-Endian中,对于bit系列中的序号编排情势如下(以双字节数0x8B8A为例):
bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+-----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+----------------------------------------+
图 2:Big-Endian的bit体系编码格局
2.2 Little-Endian
微处理器种类布局中 后生可畏种描述多字节存款和储蓄顺序的术语,在此种体制中最不重大字节(LSB)贮存在最低等的地址上。选用这种体制的微型机有PDP-11、VAX、英特尔体系微电脑微风姿罗曼蒂克部分网络通讯设施。该术语除了陈诉多字节存款和储蓄顺序外还时常用来说述多少个字节中各种比特的排泄次序。

+----------+
| 0x12 |<-- 0x00000021
+----------+
| 0x34 |<-- 0x00000020
+----------+

图3:双字节数0x1234以Little-Endian的办法存在开头地址0x00000020中
 在 Little-Endian中,对于bit体系中的序号编排和Big-Endian无独有偶反而,其艺术如下(以双字节数0x8B8A为例):
bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+-----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+-----------------------------------------+
图 4:Little-Endian的bit种类编码方式
在意:经常大家说的主机序(Host Order)正是据守Little-Endian准绳。所以当两台主机之间要透过TCP/IP公约举办通讯的时候就需求调用相应的函数举行主机序 (Little-Endian)和互联网序(Big-Endian)的转换。
运用 Little-endian格局的CPU对操作数的存放格局是从低字节到高字节,而Big-endian形式对操作数的寄放方式是从高字节到低字节。 32bit宽的数0x12345678在Little-endian情势CPU内部存款和储蓄器中的存放方式(假诺从地址0x4000始发寄放)为:
                                          内部存款和储蓄器地址     0x4000     0x4001     0x4002     0x4003
                                          贮存内容     0x78        0x56        0x34         0x12
而在Big- endian情势CPU内部存款和储蓄器中的存放格局则为:
                                          内部存款和储蓄器地址     0x4000     0x4001     0x4002     0x4003
                                          贮存内容     0x12         0x34        0x56         0x78
切实的分化如下:
必发365电子游戏 1
必发365电子游戏 2
三、Big-Endian和Little-Endian优缺点
Big-Endian优点:靠首先提取高位字节,你总是能够由看看在摆动地方为0的字节来分明那么些数字是 正数照旧负数。你不要知道那个数值有多少长度,

要么您也无须过部分字节来看这一个数值是或不是带有符号位。那么些数值是以它们被打字与印刷出来的相继存放的,所以从二进制到 十进制的函数特别实用。

进而,对于分歧供给的机械,在两全存取方式时就能够差别。

Little-Endian优点:提取贰个,三个,多个恐怕更加长字节数据的汇编指令以与其他具有格式雷同的章程张开:首先在摇摇地址为0的地点领取最低位的字节,

因为地点偏移和字节数是一定的涉及,多重精度的数学函数就相对地轻巧写了。

只要你扩大数字的值,你或者在侧边扩张数字(高位非指数函数供给更多的数字)。 由此, 平日需求追加两位数字并活动存款和储蓄器里全体Big-endian顺序的数字,

把全部数向右移,这会追加电脑的工作量。但是,使用Little- Endian的存款和储蓄器中不根本的字节可以存在它原来之处,新的数能够存在它的入手的上位地址里。

那就表示Computer中的有些总计能够变得尤其简约和飞快。
四、请写二个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1。

 1 int checkCPU(void)  
 2 {  
 3     union  
 4     {  
 5         int a;  
 6         char b;  
 7     }c;  
 8     c.a = 1;  
 9     return (c.b == 1);  
10 } 

剖析:由于二只体union的寄存顺序是有着成员都从低地址先导存放,利用该性格就能够轻巧地收获了CPU对内存采取Little- endian照旧Big-endian情势读写。

说明:
1  在c中,联合体(共用体)的数额成员都以从低地址开端贮存。
2  假如小端形式,由低地址到高地址c.a贮存为0x01 00 00 00,c.b被赋值为0x01;
  ————————————————————————————
   地址 0x00000000 0x00000001 0x00000002 0x00000003
   c.a  01         00         00         00
   c.b  01         00        
  ————————————————————————————  
3  倘若多方面格局,由低地址到高地址c.a存放为0x00 00 00 01,c.b被赋值为0x0;
  ————————————————————————————
   地址 0x00000000 0x00000001 0x00000002 0x00000003
   c.a  00         00         00         01
   c.b  00         00                 
  ————————————————————————————  
4  依据c.b的值的情事就能够判明cpu的方式了。

举个例子,一个16进制数是 0x11 22 33,其存放的岗位是
地址0x3000 中存放11
地址0x3001 中存放22
地址0x3002 中存放33
连起来就写成地址0x3000-0x300第22中学存放了数据0x112233
而这种存放和代表方法,刚好符合大端。
此外四个相比较好明白的写法如下:

 1 bool checkCPU()     // 如果是大端模式,返回真  
 2 {  
 3     short int test = 0x1234;  
 4   
 5     if( *((char *)&test) == 0x12)     // 低地址存放高字节数据  
 6         return true;  
 7     else  
 8         return false;  
 9 }  
10   
11 int main(void)  
12 {  
13     if( !checkCPU())  
14         cout<<"Little endian"<<endl;  
15     else  
16         cout<<"Big endian"<<endl;  
17   
18     return 0;  
19 }

依旧下边三种写法也是足以的

 1 int main(void)  
 2 {  
 3     short int a = 0x1234;  
 4     char *p = (char *)&a;  
 5   
 6     if( *p == 0x34)  
 7         cout<<"Little endian"<<endl;  
 8     else  
 9         cout<<"Big endian"<<endl;  
10   
11     return 0;  
12 }  
13   
14 int main(void)  
15 {  
16     short int a = 0x1234;  
17     char x0 , x1;  
18   
19     x0 = ((char *)&a)[0];  
20     x1 = ((char *)&a)[1];  
21   
22     if( x0 == 0x34)  
23         cout<<"Little endian"<<endl;  
24     else  
25         cout<<"Big endian"<<endl;  
26   
27     return 0;  
28 }  

 

互连网字节序定义:收到的首先个字节被看成高位对待,那将要求发送端发送的第一个字节应当是高位。而在出殡和下葬端发送数据时,发送的率先个字节是该数字在内部存款和储蓄器中开局部址对应的字节。可以预知多字节数值在殡葬前,在内部存款和储蓄器中数值应该以多方法存放。

互联网字节序说是大端字节序。

htons:把unsigned short类型从主机序转换来网络序

htonl:把unsigned long类型从主机序转变来网络序

ntohs:把unsigned short类型从网络序转换成主机序

ntohl:把unsigned long类型从互联网序转产生主机序

(那多少个API能够如此记,s表示short,l表示long,n表示network,h表示host)

别的:char类型是不曾字节序的难点的,独有超越三个字节的数据类型才有字节序的标题。在互连网程序开辟时 或是跨平台开采时 也相应注意保管只用后生可畏种字节序 不然双方的解释不相符就能产生bug。

举例说我们经过网络发送0x12345678那一个整形,在80X86平高雄,它是以小端法寄存的,在出殡和下葬前需求运用系统提供的htonl将其转变来大端法寄放,如图2所示。

字节序测量检验程序

不一样cpu平台上字节序日常也不生机勃勃致,下边写个大致的C程序,它能够测验不一样平台上的字节序。

#include <stdio.h>
#include <netinet/in.h>
int main()
{
    int i_num = 0x12345678;
    printf("[0]:0x%xn", *((char *)&i_num + 0));
    printf("[1]:0x%xn", *((char *)&i_num + 1));
    printf("[2]:0x%xn", *((char *)&i_num + 2));
    printf("[3]:0x%xn", *((char *)&i_num + 3));
10   
11      i_num = htonl(i_num);
12      printf("[0]:0x%xn", *((char *)&i_num + 0));
13      printf("[1]:0x%xn", *((char *)&i_num + 1));
14      printf("[2]:0x%xn", *((char *)&i_num + 2));
15      printf("[3]:0x%xn", *((char *)&i_num + 3));
16   
17      return 0;
18 

在80X86CPU平台上,实施该程序获取如下结果:
[0]:0x78
[1]:0x56
[2]:0x34
[3]:0x12

[0]:0x12
[1]:0x34
[2]:0x56
[3]:0x78

深入分析结果,在80X86阳台上,系统将多字节中的低位存款和储蓄在变量开头地址,使用小端法。htonl将i_num转变来互连网字节序,可以预知网络字节序是大端法。

计算点:80X86利用小端法,网络字节序使用大端法。

 

整数字节序调换      整个进度从该值的MSB和LSB开始沟通,直到沟通至该值的中间点,唯豆蔻年华的难题在于,由于无法大约的把对象(构造型数据)调换为字节数组去用单意气风发的通用 函数调换字节,所以供给领会什么样字节序须求转移,比如把内存中的struc或class写入文件时,要科学的转变字节序,便供给了解里面每一个数据成员的职分及大小,并依附每种成员的尺寸顺序开展适度的转变

1 //对应int32大小的成员 的转换 范例   
2 int32_t swapInt32(int32_t value)  
3 {  
4      return ((value & 0x000000FF) << 24) |  
5                ((value & 0x0000FF00) << 8) |  
6                ((value & 0x00FF0000) >> 8) |  
7                ((value & 0xFF000000) >> 24) ;  
8 }

 

平常来说,在通信软件中,思考大小尾是八个不行职业且严俊的做法,大家无法假定全部的通讯都在相像种系列布局下办事。
日常的话,除了intel 80x86星罗棋布微处理器是小尾构造,绝超越四分之二微机均为大尾构造,如sparc类别/power类别/moto的68类别等。互联网字节顺序也是大尾的。

在编解码时,特别需求注意大小尾难点。在每处使用抢先三个byte的地点,最棒使用转变函数(hton*和ntoh*点不清或自写均可)

之所以,当你的通讯软件要和任何机器上的通讯软件(模块)通讯时,凡是编解码等地方选拔了超过1个字节的数据类型,都最佳应用调换函数。在有些socket管理中,也急需增多转换函数(如ipaddr布局的填充等处),其余一些自家已经包含相关处理,就能够不用加。

 

 具体贯彻:

  1  typedef unsigned short int uint16;
  2 
  3 typedef unsigned long int uint32;
  4 
  5  
  6 
  7 // 短整型大小端互换
  8 
  9 #define BigLittleSwap16(A)  ((((uint16)(A) & 0xff00) >> 8) | 
 10 
 11                             (((uint16)(A) & 0x00ff) << 8))
 12 
 13  // 长整型大小端互换
 14 
 15  
 16 
 17 #define BigLittleSwap32(A)  ((((uint32)(A) & 0xff000000) >> 24) | 
 18 
 19                             (((uint32)(A) & 0x00ff0000) >> 8) | 
 20 
 21                             (((uint32)(A) & 0x0000ff00) << 8) | 
 22 
 23                             (((uint32)(A) & 0x000000ff) << 24))
 24 
 25 
 26  // 本机大端返回1,小端返回0
 27 
 28 int checkCPUendian()
 29 
 30 {
 31 
 32        union{
 33 
 34               unsigned long int i;
 35 
 36               unsigned char s[4];
 37 
 38        }c;
 39 
 40  
 41 
 42        c.i = 0x12345678;
 43 
 44        return (0x12 == c.s[0]);
 45 
 46 }
 47 
 48  
 49 
 50 // 模拟htonl函数,本机字节序转网络字节序
 51 
 52 unsigned long int t_htonl(unsigned long int h)
 53 
 54 {
 55 
 56        // 若本机为大端,与网络字节序同,直接返回
 57 
 58        // 若本机为小端,转换成大端再返回
 59 
 60        return checkCPUendian() ? h : BigLittleSwap32(h);
 61 
 62 }
 63 
 64  
 65 
 66 // 模拟ntohl函数,网络字节序转本机字节序
 67 
 68 unsigned long int t_ntohl(unsigned long int n)
 69 
 70 {
 71 
 72        // 若本机为大端,与网络字节序同,直接返回
 73 
 74        // 若本机为小端,网络数据转换成小端再返回
 75 
 76        return checkCPUendian() ? n : BigLittleSwap32(n);
 77 
 78 }
 79 
 80  
 81 
 82 // 模拟htons函数,本机字节序转网络字节序
 83 
 84 unsigned short int t_htons(unsigned short int h)
 85 
 86 {
 87 
 88        // 若本机为大端,与网络字节序同,直接返回
 89 
 90        // 若本机为小端,转换成大端再返回
 91 
 92        return checkCPUendian() ? h : BigLittleSwap16(h);
 93 
 94 }
 95 
 96  
 97 
 98 // 模拟ntohs函数,网络字节序转本机字节序
 99 
100 unsigned short int t_ntohs(unsigned short int n)
101 
102 {
103 
104        // 若本机为大端,与网络字节序同,直接返回
105 
106        // 若本机为小端,网络数据转换成小端再返回
107 
108        return checkCPUendian() ? n : BigLittleSwap16(n);
109 
110 }

 

大小端难点重要涉及的好坏单字节非字符串外的此外数据的意味和传递,如short型、int型等。大端和小端有其分其他优...

                  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
0x4001
存放内容
0x34
0x12

而在Big-endian格局CPU内部存款和储蓄器中的贮存方式则为:

内存地址
0x4000
0x4001
存放内容
0x12
0x34

32bit宽的数0x12345678在Little-endian格局CPU内部存款和储蓄器中的贮存情势(倘诺从地址0x4000始发寄存)为:

内存地址
0x4000
0x4001
0x4002
0x4003
存放内容
0x78
0x56
0x34
0x12

而在Big-endian情势CPU内部存款和储蓄器中的贮存形式则为:

内存地址
0x4000
0x4001
0x4002
0x4003
存放内容
0x12
0x34
0x56
0x78

一起体union的存放顺序是富有成员都从低地址开头存放,面试者的解答利用该性子,轻巧地收获了CPU对内部存款和储蓄器接收Little-endian照旧Big-endian方式读写。假如什么人能当场交付那一个解答,那几乎正是多个天分的程序猿。

 

 

补充:

所谓的多边情势,是指多少的不及(正是权值十分的小的背后那二个人)保存在内部存储器的高地址中,而数据的要职,保存在内部存款和储蓄器的低地址中,那样的储存格局有一些儿相似于把多少当做字符串顺序管理:地址由小向大扩张,而数据从高位往低位放;    所谓的小端格局,是指多少的未有保存在内部存款和储蓄器的低地址中,而数 据的上位保存在内部存款和储蓄器的高地址中,这种存储方式将地点的音量和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和大家的逻辑方式大器晚成致。    为何会有大小端情势之分呢?那是因为在微电脑种类中,大家是以字节为单位的,每种地点单元都对应着一个字节,叁个字节为 8bit。但是在C语言中除去8bit的char之外,还会有16bit的short型,32bit的long型(要看现实的编写翻译器),其它,对于位数大于 8位的微微处理机,举例15个人照旧叁十五个人的微型机,由于寄放器宽度超越叁个字节,那么自然存在着三个万风姿洒脱将多少个字节计划的问题。因此就招致了三头存款和储蓄形式和小 端存款和储蓄形式。比方多少个16bit的short型x,在内部存储器中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端格局,就将0x11放在低地址中,即0x0010中,0x二十二人居高地址中,即0x0011中。小端方式,适逢其会相反。大家常用的X86构造是小端情势,而KEIL C51则为多边情势。比较多的ARM,DSP都为小端方式。有个别ARM微处理机还足以由硬件来采摘是多方面方式也许小端方式。

 

   上边这段代码能够用来测量试验一下您的编译器是多方面方式大概小端形式:

 

short int x; char x0,x1; x=0x1122; x0=((char*)&x)[0]; //低地址单元 x1=((char*)&x)[1]; //高地址单元 若x0=0x11,则是多方面; 若x0=0x22,则是小端...... 下边包车型地铁次序还可以看见,数据寻址时,用的是不比字节的地点。

 


怎么时候要拓宽高低等字节序的调换?  

short 也许 long的数码在张开通讯的时候最棒养成:  1、发送的时候利用:htons(l)  2、接收的时候使用:ntohs(l)  而毫不理会两侧的通讯是或不是须要那样做~~  当然了相同作者都无须int型的数目通讯,平昔都以字符串通讯,发送方利用sprintf协会,选拔方利用atoi进行退换~~


 

端情势(Endian)的这一个词出自Jonathan 斯维夫特书写的《Gulliver游记》。那本书依照将鸡蛋敲开的章程不一致将有所的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从终端起初将鸡蛋敲开的人被归为Littile Endian(那句话最佳形象)。小人国的国内战役就源于吃鸡蛋时是毕竟从大洋(Big-Endian)敲开依旧从小头(Little-Endian)敲开。在Computer业Big Endian和Little Endian也差不离引起一场战乱。在测算机产业界,Endian代表数据在存款和储蓄器中的存放顺序。下文举个例子表明在计算机中山高校小端格局的差距。

只要将三个叁11个人的整数0x12345678存放到二个整型变量(int)中,这几个整型变量选拔大端可能小端格局在内部存款和储蓄器中的存款和储蓄由下表所示。为简便起见,本文使用OP0表示一个三10位数据的参天字节MSB(Most Significant Byte),使用OP3表示二个叁十五人数据低于字节LSB(Least Significant Byte)。

 

地址偏移

大端模式

小端模式

0x00

12(OP0)

78(OP3)

0x01

34(OP1)

56(OP2)

0x02

56(OP2)

34(OP1)

0x03

78(OP3)

12(OP0)

 

小端:较高的有效字节贮存在较高的的存款和储蓄器地址,超级低的有效字节贮存在非常的低的存储器地址。 大端:较高的有效字节寄放在十分的低的存储器地址,相当低的有效字节存放在较高的存款和储蓄器地址。生龙活虎经将叁个公斤个人的整数0x1234寄存到一个短整型变量(short)中。这几个短整型变量在内部存款和储蓄器中的存款和储蓄在大小端情势由下表所示。

 

地址偏移

大端模式

小端模式

0x00

12(OP0)

34(OP1)

0x01

34(OP1)

12(OP0)

 

由上表所知,采取高低模式对数码举行贮存的最首要分歧在于在寄存的字节顺序,大端格局将高位寄放在低地址,小端情势将高位贮存在高地址。接收大端方式展开数量寄存相符人类的平时思维,而接受小端格局张开数据寄存利于Computer管理。到近些日子结束,选用大端只怕小端举办多少寄放,其孰优孰劣也从没下结论。

局地微型机系统采纳了小端情势进行数量贮存,如AMD的跑马。有的微电脑系统利用了多方情势张开数量存放,如IBM非晶态半导体和Freescale的PowerPC微电脑。不只有对于电脑,一些外设的规划中也存在着使用大端也许小端实行多少寄存的接纳。

故而在叁个Computer系统中,有十分的大恐怕存在多方面和小端格局还要设有的景色。那意气风开掘象为系统的软硬件设计带给了十分的大的麻烦,那必要系统规划技术员,必须深切通晓大端和小端方式的歧异。大端与小端方式的差异体今后一个计算机的置放器,指令集,系统总线等相继档次中。

【用函数推断系统是Big Endian依然Little Endian】

//若是字节序为big-endian,重返true; //反之为   little-endian,再次回到false

bool IsBig_Endian() {     unsigned short test = 0x1234;     if(*( (unsigned char*) &test ) == 0x12)        return TRUE;    else        return FALSE;

 

}//IsBig_Endian()

 

附:

  大小端的分度值是 byte,即每三个byte都是依照符合规律顺序,可是byte组装成一个int 也许是 long等时各样byte的安顿地方差别


家喻户晓,相像生龙活虎组数据,存款和储蓄和象征的生机勃勃后生可畏能够是种类的,也等于储存和表示格式是二种的[1]。相同的多少,转换来二进制之后,在不相同的微计算机存款和储蓄器中的内部表示也许有分其他,那会对编制程序爆发一定的影响。本文首要探究大小端存款和储蓄格局对编制程序的震慑及在编程时应接受的攻略。 1 大小端存款和储蓄情势概述 Computer中的存款和储蓄器(内部存款和储蓄器卡塔尔由一大波的储存元构成。存款和储蓄元是存款和储蓄器的小不点儿物理组成单位,用来贮存在壹位二进制数0或1。把这几个囤积元按相近的位数(常常是1字节8位的1, 2, 4, 8倍卡塔尔(قطر‎划分成组,组内全部存款和储蓄元同时读出或写入消息,即为存储单元[2]。每种存款和储蓄单元都有二个无比的号码,叫做单元地址。存款和储蓄单元是CPU访谈存款和储蓄器的主导单位,CPU通过单元地址访问(读或写卡塔尔国相 应的存款和储蓄单元。差异的Computer,存款和储蓄单元地址的编纂情势有所差异。假诺打开编址的细卡片飞机地方是字,称为按字编址,如图1 (a卡塔尔所示。如若编址的蝇头单位是字节,则称按字节编址。因而, CPU一回访谈一个存款和储蓄单元就大概拜访若干个独立编址的字节,图1(b卡塔尔国为PDP-11机器,三个存款和储蓄单元寄放2个字节,低字节用偶地址,高字节用奇地址,字地址是2的翻番,即它的低字节的地点。图1(c卡塔尔为IBM-370机器,一个存款和储蓄单元存放4个字节,字地址是4的大背头倍,即它的高字节之处(与图1(b卡塔尔国所暗暗表示况反而卡塔尔(قطر‎。图1 存款和储蓄器的不如编址格局按字节编址是前段时间存款和储蓄器编址方式的主流,因为数量管理的细小单位是字节。从软件角度看,存款和储蓄器正是多个异常的大的字节数组。经常,CPU和编写翻译器使用区别的格式来编码数据,如不一样长度的卡尺头和浮点数,进而扶持多样数据类型。程 序中,先定义那些品种的变量,到内部存储器中分配字节空间,当CPU读写这几个变量,即访谈内部存储器时,往往依照数据类型的不一致,叁回可读写若干个字节。对于多于二个字节的数量(平时为字节长度的2N倍,N=1, 2, 3卡塔尔国,在存款和储蓄器中有三种存款和储蓄情势,即定义半字、字、双字与字节之间的呼应关系的三种炫丽机制[3]。朝气蓬勃种是数据的低字节部分存放在内存低地址处,高字节部分存放在内部存款和储蓄器高 地址处,称为小端字节顺序存款和储蓄法,又称小端存款和储蓄方式;另黄金时代种是高字节数据贮存在低地址处,低字节数据贮存在高地址处,称为大端字节顺序存储法,又称大端存款和储蓄模。简单看出,图1(b卡塔尔国所示为小端形式,而图1(c卡塔尔即为大端格局。扶植多边存款和储蓄形式只怕小端存款和储蓄情势,并不设有本领原因,只是提到到计算机商家的立场和习于旧贯。 2 存款和储蓄情势分裂而引致的主题素材对于超越十分之五技士来说,机器的字节存储顺序是全然不可以知道的,无论哪黄金时代种存款和储蓄形式的微管理机编写翻译出的前后相继都会获取平等的结果。即对于同少年老成段源代码,单独在小端机器上编写翻译运转,其结果与独立在多方机器上编写翻译运维的结果形似,尽管同三个多少在大大小小端格式下的内部存款和储蓄器表示有分别,但在运用程序猿和客户眼里,插手算术逻辑运算、写入读出的数额却是无差其余。可是,有个别情状下,字节顺序会产生难点。

  1. 1 UNIX主题素材———程序可移植性难点最初在将UNIX操作系统的早期版本从PDP-11移植到IBM机器上时,数据“UNIX”在十七个人字长的小端格式的PDP-11上被代表为2个字4个字节,当被移植到多方存款和储蓄情势的IBM机器上时,就能够形成“NUXI”,那被喻为UNIX难点。由此,当在分歧存款和储蓄顺序的微型机间进行程序移植时,须求非常注意存款和储蓄格局的震慑。
  2. 2 阅读、解释、分享二进制数据的主题材料对同黄金年代段可执路程序举行反汇编,使用反汇编器阅读机器级二进制代码时,在不相同存储格局的微机上会见到差别的结果;在解释、分享以二进制格式存款和储蓄的多寡和应用掩码时,不一致的蕴藏顺序会得出不相同的结果,举个例子,某31位小端机器,存款和储蓄某常量0xE48623A0到某二进制文件,在多边格局下读出的是0xA02386E4,若把该多少作为IPv4地址,则存款和储蓄并采纳方便的掩码进行按位与运算也得思考到存储形式的熏陶。
  3. 3 互联网数据传输的主题材料当分歧存款和储蓄格局的微型机之间通过网络传递二进制数据时,会时有发生高低字节翻转现象,举例,从30位小端机器,发送某常量0x01234567,发送和选拔缓冲区内(地址从低到高卡塔尔国的字节顺序为0x67、0x45、0x23、0x01,接收该多少的对方机器为 三11人民代表大会端方式,则读出的数值是0x67452301,相比较原值,高低字节交流了职分。 3 编制程序时可采纳的计谋编制程序时,应构思该接受是还是不是与存储情势相关,若供给在分化存储格局的微型机之间移植程序、分享数据、互联网通讯,能够品尝以下对策。如若程序移植,则在前后相继中增添如下的预编写翻译条件,针对不一致存款和储蓄情势,分别管理,然后在头文件中定义当前计算机和编写翻译器帮助的囤积形式,如: #define Little-End #ifdefBig_End   …… #endif #ifdefLittle_End   …… #endif 假使音信分享,则有二种减轻办法: (1卡塔尔以单大器晚成存款和储蓄顺序分享数据,只需解释大器晚成种格式,所以解码轻易; (2卡塔尔(قطر‎允许各主机以分歧的存款和储蓄顺序分享数据,但需标志出哪类情势,无需对数据的原顺序举行中间转播,所以编码轻便,当发送方编码和接受方解码采纳相像种存款和储蓄方式时,无需调换字节顺序,能够拉长通讯成效。

假设互连网通讯,能够参见并依据TCP/IP公约定义的规范的网络字节顺序,由发送方微处理机先在此中间将发送的数码转变来网络正式,而接受方微处理器再将互连网正式转变为它的内部表示。Beck雷应用程序接口定义了风姿洒脱套调换函数,如:函数htonl和htons分别将三14人长整型和15个人短整型数值从主机字节顺序转形成互连网字节顺序;而函数ntohl和ntohs则将互连网字节顺序转化为主 机字节顺序。 4 案例剖析ZLG/IP可运维于多方机器,也可运维于小端机器,涉及程序的可移植性; ZLG/IP是嵌入式互连网通信合同,必然关联七个主机间的数目分享和网络传输;由大小端存储方式区别而引致的标题,ZLG/IP都会蒙受,它是什么缓和的吧?限于篇幅,这里仅摘录IP. c中IP报头的出殡和安葬、校验、采取函数的部分源代码。存款和储蓄方式差别不会影响IP报头的字节变量成员的读写,也不会默化潜移IP地址的读写(IP地址按大端顺序选取字节数组存款和储蓄卡塔尔(英语:State of Qatar),所以,只选择IP报头的16个人半字变量成员作案例解析。

  1. 1 发送函数 原版本定义了八个有个别字节数组,无论在哪类存款和储蓄形式下编写翻译运营,均将半字变量拆分成八个字节,高字节写入低地址,低字节写入高地址,即直接按大端顺序写入字节数组,保障发送和接纳缓冲区的内存表示的风流倜傥致性,即互联网传输的IP报头的黄金年代致性。 eip e_ip; uint8 IpHeadUint8[20]; …… e_ip. TotalLen=(*TxdData). length+20; IpHeadUint8[2]=(e_ip.TotalLen&0xff00)>>8; IpHeadUint8[3]=e_ip.TotalLen&0x00f;f …… e_ip.Crc=CreateIpHeadCrc(IpHeadUint8); IpHeadUint8[10]=(e_ip. Crc&0xff00)>>8; IpHeadUint8[11]=e_ip.Crc&0x00f;f …… TxdIpData.DAPTR=IpHeadUnit8; Send_Ip_To_LLC (&TxdIpData, e_ip. DestId, num卡塔尔(قطر‎; 笔者的做法是使用共用体类型union ip-rc完结,能够节约局部字节数组空间,大小端境况有别于对待,大端形式下,直接写入原值;小端情势下,先写入原值,再对该变量成员作高低字节转换,即最后写入的值不相同(与原值字节顺序相反卡塔尔(قطر‎,内存代表却变的一致了(原值的多方面顺序卡塔尔。   union ip_rc {eip e_ip;        struct {uint16 wordbuf[10]; } words; };   union ip_rc IpHead;   ……   IpHead. e_ip. TotalLen=(*TxdData). length+20; #ifdefLittle_End   IpHead. e_ip. TotalLen=swap_ int16( IpHead e_ ip. To- talLen); #endif   ……   IpHead. e_ip. Crc=CreateIpHeadCrc_1 ( IpHead. words. wordbuf); #ifdefLittle_End   IpHead. e_ip. Crc=swap_int16(IpHead. e_ip. Crc); #endif   ……   TxdIpData. DAPTR=(uint8* ) & IpHead. e_ip;   Send_Ip_To_LLC (& TxdIpData, IpHead. e_ip. DestId, num卡塔尔(قطر‎; 4. 2 IP报头校验和总结函数 无论哪一种存款和储蓄方式下,为了确认保障校验和结果的惟意气风发性,原版本对传递过来的8位字节数组(内部存储器表示默以为大端顺序卡塔尔国强迫按半字二十一个人民代表大会端顺序读出及求和。 union w Crc: //类型union w在ip. h中定义,存款和储蓄形式分裂,定义也不及 Crc. dwords=0; for ( i=0; i<10; i++卡塔尔(英语:State of Qatar) Crc. dwords=Crc. dwords+ ((uint 32卡塔尔(英语:State of Qatar)Ip[2* i]<<8) + (uint32)Ip[2* i+1]; 笔者完成的校验和总括函数越来越精短更通用,形参十五个人半字数组是规定不改变的多方字节顺序,大端格局下,读出的IpH[ i]正是原值,直接助长就能够;小端形式下,读出IpH[ i]后必得调换高低字节,才是那个时候写入的原值,然后再加上。 uint32 temp=0; for ( i=0; i<10, i++卡塔尔(英语:State of Qatar) { #ifdefBig_End  temp=temp+(uint32) IpH[ i]; #从他们的存储方式可以看出。endif #ifdefLittle_End  temp=temp + (uint32) (swap_int16 (IpH[ i])); #endif } 4. 3 选用函数 原版本中,传递过来的IP报头是多方面顺序字节数组中的数据,在多方形式下读出时,正是科学的原值,在小端处境下编译运转时,内部存款和储蓄器表示是多方面顺序,却按小端顺序读出,结果值与原值高低字节顺序相反,因而,要将读出的结果进行高低字节交流,技术收获不错的原值。 #ifdefBig_End  PackedLength=((eip* )RecData)->TotalLen; #endif #ifdefLittle_End  PackedLength=((eip* )RecData)->TotalLen;  Ltemp=PackedLength&0x00f;f  PackedLength=(PackedLength&0xff00)>>8;  PackedLength=PackedLength+(Ltemp<<8); #endif 而小编精减了代码,读操作是随意哪类存款和储蓄情势下都存在的,能够统意气风发出来,之后针对小端形式的区别平常情形,进行高低字节转变,变回原值。  PackedLength=((eip* )RecData)->TotalLen; #ifdefLittle_End  PackedLength=swap_int16 (PackedLength)); #endif 通过阅读源码得悉, ZLG/IP约定:无论在哪个种类存储方式的机器上编写翻译运转, IP报头在发送和接纳缓冲区中的字节顺序表示为多边字节顺序。那样的预约有三个平价: (1)保险了网络通讯的数据包报头的字节顺序大器晚成致,产生互连网字节顺序的规范,当在通讯双方的两样的积累情势下读出时,由终端Computer种类和睦转变; (2卡塔尔(英语:State of Qatar)方便了报头校验和的简政放权,无论大小端存款和储蓄形式,风流洒脱致按大端 顺序读出,有限协理了校验和的惟后生可畏性。 5 结语 由上述解析可知,本文所写代码能够节约局地数组空间,代码量更加少,函数模块更通用。因而,能够特别简练ZLG/IP中ICP报头、UDP报头的出殡和下葬、核准、选取源代码。

怎么时候要进行高低档字节序的转换?  

short 只怕 long的数量在扩充通讯的时候最棒养成:  1、发送的时候使用:htons(l)  2、选用的时候利用:ntohs(l)  而毫无理睬两侧的通讯是还是不是供给这么做~~  当然了常常自身都不要int型的数据通讯,一直都是字符串通讯,发送方利用sprintf组织,接受方利用atoi进行改造~~