在计算机中是以字节为单位,每个地址对应一个字节,一个字节8bit。在C中,除了8bit的char以外,还有16bit的short,32位的int,64位long,当然具体要由编译器决定,可以通过sizeof来获取不同类型在内存中占用的字节数。在计算机系统中,当物理单位的长度大于1个字节时,就要区分字节顺序。常见的字节顺序有两种:Big Endian(High-byte first)和Litter Endian(Low-byte first),当然还有其他字节顺序,但不常见,例如Middle Endian。

一、最高有效位、最低有效位

要理解Big Endian和Little Endian,首先要搞清楚MSB和LSB。

1、MSB(Most Significant Bit)最高有效位

在一个n位二进制数字中n-1位,也就是最左边的位。

2、LSB(Least Significant Bit)最低有效位

指最右边的位。

例如:一个int类型的整型123456789

二进制表达方式:0000 0111 0101 1011 1100 1101 0001 0101(从右向左,每4bit对齐,最左边(高位)不够用0补齐)

十六进制表达方式:0 7 5 B C D 1 5

按照上述关于MSB和LSB的意思,在二进制表达方式中,bit从0开始,从右向左,bit0为最低有效位,而bit23为最高有效位。而我们一般称左边的0x07为高位字节,0x15为低位字节。

再通俗一点解释就是:8421码的,8这端为高位,1这端为低位,相应的字节则分别称为高位字节和低位字节。

二、内存地址

在内存中,多字节对象都是被存储为连续的字节序列。例如在C语言中,一个类型为int的变量n,如果其存储的首个字节的地址为0x1000,那么剩余3个字节的地址将存储在0x1001~0x1003。总之,不管具体字节顺序是以什么方式排列,内存地址的分配一般是从小到大的增长。我们常把0x1000称为低地址端,把0x1003称为高地址端。

三、大端和小端

搞清楚MSB、LSB、高位字节、低位字节、内存地址之后,再理解大端和小端,就相当容易了,先看看概念:

小端Little Endian:低字节存放在低地址,低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

大端Big Endian:高字节存放在低地址,即高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

以二节中的例子int类型整数123456789为例:

小端在内存中排列:0x15 0xCD 0x5B 0x07 (低位在前)

大端在内存中排列:0x07 0x5B 0xCD 0x15 (高位在前)

从例子中可以看出小端比较符合人的思维,而大端则看上去非常直观。

注:

1、例子中是假设编译器支持int为32位的前提下,如果是16位,那大端的排列则为:0xCD 0x15 0x07 0x5B。

2、大小端一般是由CPU架构决定,常见的Intel、AMD的CPU使用的是小端字节序,而PowerPC使用的是大端字节序,有些ARM处理器还可以选择用大端还是小端模式,具体请自行查阅。

3、c#中,字节序跟编译平台所在的CPU相关,例如在Intel x86 CPU架构的windows平台中,c#采用的小端序。而Java由于其JVM屏蔽了不同CPU架构导致的字节序差异,所以默认采用大端字节序。所以,大小端模式是由CPU决定,而编译器又可能会改变这种模式。

字节序

内存地址

int(16bit)

int(32bit)

特点

小端

0x1001,0x1002,0x1003,0x1004

0x15 0xCD 0x5B 0x07

0x15 0xCD 0x5B 0x07

低地址端存储低位字节,低位在前

大端

0x1001,0x1002,0x1003,0x1004

0xCD 0x15 0x07 0x5B

0x07 0x5B 0xCD 0x15

低地址端存储高位字节,高位在前

四、网络字节序和主机字节序

网络字节序(Network Order):TCP/IP各层协议将字节序定义为Big Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

主机字节序(Host Order):整数在内存中保存的顺序,它遵循Little Endian规则(不一定,要看主机的CPU架构)。所以当两台主机之间要通过TCP/IP协议进行通信的时候就需要调用相应的函数进行主机序列(Little Endian)和网络序(Big Endian)的转换。

如果是做跨平台开发时,双方需要协商好字节序,然后根据程序运行的环境,确定是否需要字节序转换。

例如约定的通讯字节序位Big Endian,默认的windows采用的Little Endian,那收到数据后就需要做转换操作。

五、C#位操作符

这里简单记录一下C#的位操作符,方便以后自己查阅,也方便理解后面的讲解。

1、按位与&

1&0为0;0&0为0;1&1为1。

2、按位或|

1|0为1;0|0为0;1|1为1。

3、按位取反~

~1为0;~0为1。

4、按位异或^

1^1为0;0^0为0;1^0为1。相等得0,相异等1。

5、左移<<

位左移运算,将整个数向左移若干位,左移后空出的部分用0补齐。

6、右移>>

位右移运算,将整个数向右移若干位,右移后空出的部分用0补齐。

六、C#中关于大端和小端的转换

1、重复轮子

usingSystem;

namespaceFramework.NetPackage.Common

{

///

///字节序转换辅助类/// public static classEndian{

public static shortSwapInt16(this shortn)

{

return(short)(((n & 0xff) << 8) | ((n >> 8) & 0xff));

}

public static ushortSwapUInt16(this ushortn)

{

return(ushort)(((n & 0xff) << 8) | ((n >> 8) & 0xff));

}

public static intSwapInt32(this intn)

{

return(int)(((SwapInt16((short)n) & 0xffff) << 0x10) |

(SwapInt16((short)(n >> 0x10)) & 0xffff));

}

public static uintSwapUInt32(this uintn)

{

return(uint)(((SwapUInt16((ushort)n) & 0xffff) << 0x10) |

(SwapUInt16((ushort)(n >> 0x10)) & 0xffff));

}

public static longSwapInt64(this longn)

{

return(long)(((SwapInt32((int)n) & 0xffffffffL) << 0x20) |

(SwapInt32((int)(n >> 0x20)) & 0xffffffffL));

}

public static ulongSwapUInt64(this ulongn)

{

return(ulong)(((SwapUInt32((uint)n) & 0xffffffffL) << 0x20) |

(SwapUInt32((uint)(n >> 0x20)) & 0xffffffffL));

}

}

}

2、BCL库支持的函数

System.Net.IPAddress.HostToNetworkOrder、System.Net.IPAddress.NetworkToHostOrder,这两个函数的内部实现和上面重复轮子原理一模一样。

七、关于负数

在计算机中,负数以其绝对值的补码形式表示,不明白可以查阅九中贴出的相关资源。关于负数的字节序跟一般整数的字节序处理没有任何区别。

八、关于汉字编码以及与字节序的关系

1、对于gb2312、gbk、gb18030、big5,其编码某个汉字产生的字节顺序,由其编码方案本身决定,不受CPU字节序的影响。其实这几种编码的字节序和大端模式的顺序是一致的。

在使用GB2312的程序通常采用EUC储存方法,以便兼容于ASCII。浏览器编码表上的“GB2312”,通常都是指“EUC-CN”表示法。

每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。

“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上0xA0)。

由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节)0xA1(第二个字节)储存。(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。

2、UTF-8

UTF-8和gb系列编码一样,其编码某个汉字产生的字节顺序,由其编码方案决定,不受CPU字节序的影响。无论一个汉字有多少个字节,它的字节序与编码顺序保持一致。

例如汉字”严”利用utf8编码过程:

1、已知“严”的unicode编码是4E25(100111000100101),根据utf8规则可以得知其utf8编码需要三个字节。

即格式是“1110xxxx 10xxxxxx 10xxxxxx”

第一个字节前三位表示了字符“严”被编码成utf8后的编码长度,有多长,则从左开始填多少个1,如果只有1个字节,则第一个位为0。

对于编码后大于1个字节的符号,第一个字节的第四位为0,其他字节前两位均要求为10。

2、从”严“的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了“严”的utf8编码为“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

从上述过程可以看到,utf8的字节序已经由其编码方案决定,不受CPU字节序影响。

3、Unicode

Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。所以他没有要求如何存储编码后的字节,也就受CPU字节序的影响。

Unicode的具体实现包括UTF-16、UTF-32(当然也包括UTF-8,但由于其编码方式和编码后的字节序与其他Unicode编码实现有较大区别,所以单独拿出来讲解的)。

4、总结

1、网络通讯

在实际的网络通讯中,网络协议例如TCP是规定网络字节序(Network Order)是大端。而针对汉字具体使用什么编码,通讯双方要么提前约定好,要么就需要在数据包中标识好汉字具体使用的编码。

如果在网络通讯中,涉及例如UTF16这样区分大小端的编码,除非按网络协议要求采用大端模式是,否则也要事先约定好,或者在数据包中标识好使用的字节序模式。

2、文件

文件的也会存储汉字,当然也要进行编码。如果采用UTF-16这样的有字节序模式区分的编码,编码规则要求可以在文件头部的BOM(Byte Order Mark)来标记。如果没有标记,除非事先知道字节序的模式,否则只能大小端都试一遍。

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在Unicode编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FEFF在Unicode中是不存在的字符,所以不应该出现在实际传输中。UCS(Unicode的学名)规范建议我们在传输字节流前,先传输字符“ZERO WIDTH NO-BREAK SPACE”。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符“ZERO WIDTH NO-BREAK SPACE”又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符“ZERO WIDTH NO-BREAK SPACE”的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

九、参考资源

mysql是大端小端_大端和小端 - HackerVirus - 博客园相关推荐

  1. webbrowser中localhost和发布的地址_发布一款android版博客园官方app

    1.前言 博客园创立于2004年1月,是一个面向开发者的知识分享社区.自创建以来,博客园一直致力并专注于为开发者打造一个纯净的技术交流社区,推动并帮助开发者通过互联网分享知识,从而让更多开发者从中受益 ...

  2. java 雷达反射面积_毫米波雷达 - Magnum Programm Life - 博客园

    微波是通信和雷达使用的主要频段, 300Mhz ~ 300GHz.  毫米波是微波的一个子频段. 可见光,红外,激光, 由于频率不同和微波的特性有很大差异. 不同频段的电磁波在 "反射, 吸 ...

  3. java费波拉切_面试题 - 不再犯错 - 博客园

    js的基本类型有哪些?引用类型有哪些?null和undefined的区别. 如何判断一个变量是Array类型?如何判断一个变量是Number类型?(都不止一种) Object是引用类型嘛?引用类型和基 ...

  4. 触发器和java的关系_触发器-1 - java ee spring - 博客园

    ------------------------------------环境代码 create  table student (stuid varchar2(10) not null, stuname ...

  5. python命令行运行模式_[Python] 命令行模式阅读博客园的博文

    1 #-*- coding:UTF-8 -*- 2 importrequests3 from lxml importetree4 importsys5 importio6 importos7 8 9 ...

  6. 阿尔法贝塔阀原理_图总结 - 阿尔法个贝塔 - 博客园

    一.思维导图 二.概念笔记 图的存储结构 1. 邻接矩阵 定义:设图G有n (n大于等于1) 个顶点,则邻接矩阵是一个n阶方阵. 当矩阵中的 [i,j] !=0(下标从1开始) ,代表其对应的第i个顶 ...

  7. 子列和列_最大子列和 - fanlinglong - 博客园

    最大连续子序列和问题 给定k个整数的序列{N1,N2,...,Nk },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= k.最 ...

  8. python拍七游戏代码_拍七数字游戏 - Johannes-Jensen - 博客园

    最近写作业时,老师留了一道关于拍七数字游戏的题,"拍7游戏"规则是:一堆人围成一圈,开始时,任意指定一人说出数字"1"后,一圈人按顺时针方向,每人按整数由小到大 ...

  9. java编写某计算器控制台程序_计算器 - 进阶的憨狗 - 博客园

    源起 最近在看程杰著作的<大话设计模式>,全书以小菜和大鸟对话的形势,由浅入深的讲解程序的设计思想,影射出一个个设计模式.我之前虽然也使用过一些设计模式,但没有系统的学习.整理.总结,现从 ...

最新文章

  1. oracle挂堎,Oracle 冷拷备实例挂到新ORACLE时应注意问题。
  2. 梅花桩上练真功,腾讯公布机器人移动技术探索新突破
  3. 单个神经元在深度网络中的作用
  4. R语言使用caret包的preProcess函数进行数据预处理:对所有的数据列进行YeoJohnson变换(将非正态分布数据列转换为正态分布数据、可以处理负数)、设置参数为YeoJohnson
  5. springcloud 子项目怎么导入_Spring Cloud基础面试题大集合
  6. python中outside loop_Python: 'break' outside loop
  7. r - 求平均成绩_学霸秘籍:小学数学知识点例题讲解 — 平均数问题
  8. 对于Array的引用
  9. 开发转运维有什么好点的理由_芜湖好点的团购社区费用
  10. ASP.NET中Request.ApplicationPath、Request.FilePath、Request.Path、.Request.MapPath、Server.MapPath的区别...
  11. hdu 3177贪心
  12. [有限元] Ansys Workbench 实现 Edge 的分段 Pressure 的方法:SpaceClaim 中使用分割面
  13. 高清网络视频无损FLV教程
  14. LayoutInflater——inflate方法不同参数的区别
  15. Tuxera NTFS使用教程:如何在特定挂载的卷禁用文件系统缓存
  16. 无人机未来有一大波创富平台
  17. UG区域拉伸和零件透明在装配中不显示
  18. ppi 各代iphone_iPhone
  19. 录屏转gif的好用小工具ScreenToGif,免费又好用!
  20. 破解还原卡的方法总结!! 1

热门文章

  1. 如何在spss结果输出页面显示命令/运行代码
  2. 通过两个实例来理解 devtool: 'source-map' 是什么意思
  3. 怎样使用计算机的桌面助手,360桌面助手怎么用
  4. python生成模拟微信气泡图片
  5. 基于强化学习与深度强化学习的游戏AI训练
  6. 2019,苹果艰难又关键的一年
  7. Redis——有时候expire比exists更好用
  8. 【Android真机app的性能测试(CPU,内存,启动时间)】
  9. mac 破解安装 navicat
  10. 时钟容错同步算法之FTA