论大小端

   最近挺忙的,也没时间写点东西,一直在忙下一个资料片的事情,前几天在群里见有人问关于大小端的事情,这里说一下。
   对于跨平台的程序或者所用数据牵扯到不同平台的程序(例如网络编程),大小端字节序是个值得考虑的事情。本文主要讨论一下网络编程方面的大小端问题。(by peakflys)
   先来说一下几个定义:
   a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。(逻辑上的低低高高)
   b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。(像数据流一样填充)
   c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

   因为字节序往往和具体CPU架构有关,所以 如果你知道你的程序主要用户群是什么平台,为了方便或者效率,你可以除了socket端口等需要在主机字节序和网络字节序之间转换外,其余数据的传递直接无视。例如 现在很多端游 都是如此。因为现在大多数人使用的计算机都是X86体系结构的CPU+Windows操作系统,这部分用户基本就是主流玩家,其他平台的玩家,除非获得的回报率足够多,否则没必要花费太多时间关注。
   先来说一下,常见的CPU架构的字节序吧:
      Big Endian : PowerPC、IBM、Sun
      Little Endian : x86、DEC
      ARM的大小端是可选的。
   最近随着移动终端(大多为ARM处理器)和移动互联网的爆发式发展,以后的游戏平台就不得不考虑一下大小端问题了。
   大小端问题主要涉及的是非单字节非字符串外的其余数据的表示和传递,如short型、int型等。判断主机大小端的方法有很多,常见的是联合体判断法,代码如下:
01.bool isBigEndian()  
02.{  
03.    union
04.    {  
05.        int a;  
06.        char b;  
07.    }num;  
08.    num.a = 0x1234;  
09.    return ( num.b == 0x12 )   
14.}
出于效率考虑,我们有理由也完全应该 把大小端的处理放在客户端,在客户端socket过来时把服务器主机的大小端通知给客户端,这样服务器就不需要改动,直接传递数据就行,这时候可以在客户端代码中封装几个宏,在客户端在收到数据后,根据那些宏来判断是否转换以及得出转换后的数值。大小端转换最有效也是最常见的方法就是移位法:
#define __SWP16(A)   (( ((uint16)(A) & 0xff00) >> 8)    | \  
(( (uint16)(A) & 0x00ff) << 8))  

#define __SWP32(A)   ((( (uint32)(A) & 0xff000000) >> 24) | \  
(( (uint32)(A) & 0x00ff0000) >> 8)   | \  
(( (uint32)(A) & 0x0000ff00) << 8)   | \  
(( (uint32)(A) & 0x000000ff) << 24)) 
聊了那么多,可能很多人要问 为什么 主机的字节序不统一呢? 这是因为 各个CPU厂商出于不同的逻辑考量,换句话说 大端和小端有其各自的优势。我们知道计算机正常的内存增长方式是从低到高(当然栈不是),取数据方式是从基址根据偏移找到他们的位置,从他们的存储方式可以看出,大端存储因为第一个字节就是高位,从而很容易知道它是正数还是负数,对于一些数值判断会很迅速。而小端存储 第一个字节是它的低位,符号位在最后一个字节,这样在做数值四则运算时从低位每次取出相应字节运算,最后直到高位,并且最终把符号位刷新,这样的运算方式会更高效,也更符合我们手算的方式。当然这些都是自己的理解,如有不对,还望指正。
   此次评述先到此为止,要去给媳妇儿做饭吃了……

posted on 2012-08-19 12:17 peakflys 阅读(5970) 评论(5)  编辑 收藏 引用 所属分类: 服务器

评论

# re: 论大小端 2012-08-19 20:40 zaccheo

要去给媳妇儿做饭吃了……

这个是亮点。哈哈

楼主应该写个 _swp64的宏,也挺常用的  回复  更多评论   

# re: 论大小端 2012-08-19 22:54 时间矢

C语言socket编程中有专门的函数负责网络字节顺序转换的函数啊,htonl(),htons(),ntohl(),ntohs()  回复  更多评论   

# re: 论大小端 2012-08-20 09:48 peakflys

64位和32位道理一样,挺好写的,自己实现就okay了,呵呵 @zaccheo
  回复  更多评论   

# re: 论大小端 2012-08-20 09:56 peakflys

对的,那几个函数就是为了在网络字节序(也就是大端)和本地字节序间转换的,不过它提供的只有32位和16位的数值转换,实际项目中还会用到其他格式的数值类型,为了保证格式上的统一,一般都自己封装转换方法(其实那几个函数的真实实现 也是用到上面的方法实现的)@时间矢
  回复  更多评论   

# re: 论大小端 2012-08-22 15:32 Anonymous8421

dec的vax应该是LE, 它的alpha axp则是BE  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2013年1月>
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789

导航

统计

公告

人不淡定的时候,就爱表现出来,敲代码如此,偶尔的灵感亦如此……

常用链接

留言簿(4)

随笔分类

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜