端模式(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间作出选择。但某些处理器(如MIPS和IA-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:
- int testendian() {
- int x = 1;
- return *((char *)&x);
- }
Endianness对于网络通信也很重要。试想当Little Endian系统与Big Endian的系统通信时,如果不做适当处理,接收方与发送方对数据的解释将完全不一样。比如对以上C程序段中的变量d,Little 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文件里找到):
- #if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
- #define htons(A) (A)
- #define htonl(A) (A)
- #define ntohs(A) (A)
- #define ntohl(A) (A)
- #elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
- #define htons(A) ((((uint16)(A) & 0xff00) >> 8) | (((uint16)(A) & 0x00ff) << 8))
- #define htonl(A) ((((uint32)(A) & 0xff000000) >> 24) | (((uint32)(A) & 0x00ff0000) >> 8) | (((uint32)(A) & 0x0000ff00) << 8) | (((uint32)(A) & 0x000000ff) << 24))
- #define ntohs htons
- #define ntohl htohl
- #else
- #error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."
- #endif
阅读(6123) | 评论(0) | 转发(2) |