字节序

1、简介

现代的计算机系统一般采用字节(Octet, 8 bit Byte)作为逻辑寻址单位。当物理单位的长度大于1个字节时,就要区分字节序(Endianness)

字节序是指处理器在处理多字节数据时,在寄存器和内存中保存字节的顺序。为了简便起见它的英文也常常表示为 Byte Order 

目前在各种体系的计算机中通常采用的字节存储机制主要有两种:Little-Endian 和 Big-Endian。

另外还有一种不常用的字节序Middle-Endian,又称为Mixed-Endian或者PDP-Endian,它是Little-Endian 和 Big-Endian的混合体。  

我们常见的大部分处理器都采用Little-Endian,例如x86、6502、Z80、VAX以及PDP-11等;

使用Big-Endian的处理器通常是Motorola的处理器,例如:6800、68000、PowerPC 以及System/370等;

像ARM、PowerPC、Alpha、SPARC V9、MIPS、PA-RISC和IA64等体系结构支持可切换的字节序这样的特性,

这个特性可以提高效率或者简化网络设备和软件的逻辑。这种可切换的字节序被称为Bi-Endian

用于硬件上意指计算机或者传递数据时可以使用两种不同字节序中任意一种的能力。

Middle-Endian 使用很少,偶尔会在一些小型机体系中的十进制数的压缩格式中出现。 

 

2、不同字节序在内存中的存储方式

MSB(Most Significant Byte),最高有效字节,是一个数据中权值最大的那一个字节。

LSB(Least Significant Byte),最低有效字节,是一个数据中权值最小的那一个字节。

Big-Endian(BE),是指数据的高字节(MSB)保存在内存的低地址中,而数据的低字节(LSB)保存在内存的高地址中,
  这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
Little-Endian(LE),是指数据的高字节(MSB)保存在内存的高地址中,而数据的低字节(LSB)保存在内存的低地址中,
  这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

例如:整型数 0x1A2B3C4D 它的MSB是 0x1A,LSB是 0x4D,在内存中存储的方式如下:

 

 3、判断目标系统的字节序

关于这个功能的编程, 网上可以搜到各种各种的例子, 但是原理都是相同的, 都是判断多字节类型的低位地址存储的是MSB(BE)还是LSB(LE).(不考虑Middle-Endian)

/*
return value
    0 : TRUE  (host boyte order is big-endian)
    1 : FALSE 
 */
int isBigEndian(void)
{

    union {
        int i; /* at least 16 bit */
        char c;
    }un;

    un.i = 0x01; /* 0x01 is LSB */

    return (un.c == 0x01);
}

 

4、无符号整型字节序的转换

下面的代码实现了16/32/64位无符号整型大小端转换,在linux下通过使用宏定义实现的,但是原理同下面的代码一样, 具体可以参照 /usr/include/bits/byteswap.h.

#include <sys/types.h>

/* Swap bytes in 16 bit value.  */
u_int16_t ChangeEndianness16(u_int16_t value)
{
    u_int16_t result = 0;
    result |= (value & 0x00FF) << 8;
    result |= (value & 0xFF00) >> 8;
    return result;
}

/* Swap bytes in 32 bit value.  */
u_int32_t ChangeEndianness32(u_int32_t value)
{
    u_int32_t result = 0;
    result |= (value & 0x000000FF) << 24;
    result |= (value & 0x0000FF00) << 8;
    result |= (value & 0x00FF0000) >> 8;
    result |= (value & 0xFF000000) >> 24;
    return result;
}

/* Swap bytes in 64 bit value.  */
u_int64_t ChangeEndianness64(u_int64_t value)
{
    u_int64_t result = 0;
    result |= (value & 0xff00000000000000ull) >> 56; 
    result |= (value & 0x00ff000000000000ull) >> 40; 
    result |= (value & 0x0000ff0000000000ull) >> 24; 
    result |= (value & 0x000000ff00000000ull) >> 8;
    result |= (value & 0x00000000ff000000ull) << 8;
    result |= (value & 0x0000000000ff0000ull) << 24;
    result |= (value & 0x000000000000ff00ull) << 40;
    result |= (value & 0x00000000000000ffull) << 56;
    return result;
}

 

5、网络编程相关

网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,

从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节序采用Big-Endian排序方式。

这样就给编写网络程序的程序员带来一个问题,程序员必须把本地数据从主机字节序转换成网络字节序发送到主机,

同时,主机也必须把收到的数据从网络字节序转换成本地字节序。Linux中提供了如下4个函数,

其实现原理就是前2小节内容的组合(如果主机字节序是Big-Endian则返回原值,否则进行字节序转换后再返回)

#include <netinet/in.h>

/* 将主机字节序,转换成网络字节序,返回网络字节序的值 */
uint16_t htons(uint16_t host16bitvalue);  /* convert short form host to net */
uint32_t htonl(uint32_t host32bitvalue);

/* 将网络字节序,转换成主机字节序,返回主机字节序的值 */
unit16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);

  上面4个函数很容易记忆, h 代表 host, n 代表 network, s 代表 short(16bit), l 代表 long(32bit), to 就不同解释了,

需要注意的是这里的long类型即使在64位系统中, 操作数仍是32位的. 

 

6、BOM字节序标记(Byte Order Mark)

我们都知道计算机只认识2进制的数字0和1,任何字符在电脑中都是以2进制的形式存储的。

把字符转换为计算机认识的过程就叫做编码,经过编码的字符才能被计算机处理,这时经过编码后的字符称之为【内码】。

所以字符编码就是指定文字和内码之间转换的一种规则,更简单的可以理解为用几个字节去标识字符。

而所以编码规则就是,字符在字节中的存储方式。

对于UNICODE编码来说,在初期是有USC-2和USC-4两种编码方式,也就是使用2个字节和4个自己来存储字符。

而UNICODE编码的编码规则叫做UTF(Unicode Transformation Format),目前存在的有UTF7,UTF8,UTF16和UTF32这几种。

其中UTF-16规则对应USC-2编码,而UTF-32规则对应USC-4编码。而UTF-7和UTF8比较特殊。

在UCS 编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。

而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符”ZERO WIDTH NO-BREAK SPACE”。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;

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

 

编码
BOM (十六进制)
 
UTF8
EF BB BF
 
UTF16BE(大端序)
FE FF
 
UTF16LE(小端序)
FF FE
 
UTF32BE(大端序)
00 00 FE FF
 
UTF32LE(小端序)
FF FE 00 00
 
UTF-7
2B 2F 76和以下的一个字节:[ 38 | 39 | 2B | 2F ]
 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------

https://en.wikipedia.org/wiki/Endianness

http://blog.csdn.net/shaovey/article/details/4699095

http://blog.sina.com.cn/s/blog_4833ae820100jorc.html

http://www.ibm.com/developerworks/aix/library/au-endianc/index.html?ca=drs-

http://blog.csdn.net/lizhi200404520/article/details/7290193

 

posted @ 2015-06-30 15:24  LubinLew  阅读(1600)  评论(0编辑  收藏  举报