Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1069180
  • 博文数量: 139
  • 博客积分: 1823
  • 博客等级: 上尉
  • 技术积分: 3403
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 09:54
文章存档

2014年(7)

2013年(16)

2012年(48)

2011年(68)

分类: 嵌入式

2012-04-07 10:35:20

端模式(Endian)的这个词出自Jonathan Swift书写的《格列佛游记》。这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。在计算机业Big Endian和Little Endian也几乎引起一场战争。在计算机业界,Endian表示数据在存储器中的存放顺序。下文举例说明在计算机中大小端模式的区别。
大端模式
  所谓的大端模式,是指数据的高位,保存在内存的低地址中,而数据的低位,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
  例子:
   低地址                                            高地址 
   &lw---------------------------------------->>
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     12    |      34    |     56      |     78    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  在大端模式下,应该这样读: 0x12345678
  记忆方法: 地址的增长顺序与值的增长顺序相反
小端模式
  所谓的小端模式,是指数据的高位保存在内存的高中,而数 据的低位保存在内存的低地址中,这种存储模式将地址的高低和位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
  例子:
   低地址                                            高地址 
   &lw--------------------------------------->>
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     12     |      34    |     56      |     78    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  在小端模式下,应该这样读: 0x78563412
  记忆方法: 地址的增长顺序与值的增长顺序相同
 

所有计算机处理器都必须在这两种Endian间作出选择。但某些处理器(MIPSIA-64)支持两种模式,可由编程者通过软件或硬件设置一种Endian。以下是一个处理器类型与对应的Endian的简表:

·  Big Endian: Sun ,

·  Bi-Endian, 运行Big Endian模式: 运行IRIX, ,大多数系统

·  Bi-Endian, 运行Little Endian模式:   运行Ultrix,大多数DEC , 运行Linux

·  Little Endian: DEC

如何在程序中检测本系统的Endianess?可调用下面的函数来快速验证,如果返回值为1,则为Little Endian;为0则是Big Endian

  1. int testendian() {
  2.     int x = 1;
  3.     return *((char *)&x);
  4. }

       Endianness对于网络通信也很重要。试想当Little Endian系统与Big Endian的系统通信时,如果不做适当处理,接收方与发送方对数据的解释将完全不一样。比如对以上C程序段中的变量dLittle Endian发送方发出11 22 33 44四个字节,Big Endian接收方将其转换为数值0x11223344。这与原始的数值大相径庭。

为了解决这个问题,TCP/IP协议规定了专门的"网络字节次序",即无论计算机系统支持何种Endian,在传输数据时,总是数值最高位的字节最先发送。从定义可以看出,网络字节次序其实是对应Big Endian的。

     为了避免因为Endianness造成的通信问题,及便于软件开发者编写易于平台移植的程序,特别定义了一些C语言预处理的宏来实现网络字节与主机字节次序之间的相互转换。htons()htonl()用来将主机字节次序转成网络字节次序,前者应用于16位无符号数,后者应用于32位无符号数。ntohs()ntohl()实现反方向的转换。这四个宏的原型定义可参考如下(Linux系统中可在netinet/in.h文件里找到)


  1. #if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
  2. #define htons(A) (A)
  3. #define htonl(A) (A)
  4. #define ntohs(A) (A)
  5. #define ntohl(A) (A)
  6. #elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
  7. #define htons(A) ((((uint16)(A) & 0xff00) >> 8) | (((uint16)(A) & 0x00ff) << 8))
  8. #define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | (((uint32)(A) & 0x00ff0000) >> 8) | (((uint32)(A) & 0x0000ff00) << 8) | (((uint32)(A) & 0x000000ff) << 24))
  9. #define ntohs htons
  10. #define ntohl htohl
  11. #else
  12. #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."
  13. #endif
阅读(6123) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~