标签:
现代计算机一般采用字节(Octet or Byte)作为逻辑寻址单位,当物理长度大于一个字节时,就要区分字节顺序(Byte Order)。例如在C语言中,除了8bit char外,还有16bit的short和32bit的int;此外对于大于8位的处理器,如16位或32位处理器,由于寄存器宽度大于一个字节,也存在多个字节排列的问题。常见的字节顺序有两种:Big-Endian和Little-Endian。
大端序(Big-Endian)即是将其最高有效位(Most Sigificant Bit)放在内存的低地址端,最低有效位(Little Sigificant Bit)放在内存的高地址端;小端序(Little-Endian)则恰好相反。若将整型数据0x12345678存入内存,其在不同的系统中表示如下:
0 --> 31
0x12 |
0x34 |
0x56 |
0x78 |
Big-Endian
0 --> 31
0x78 |
0x56 |
0x34 |
0x12 |
Little-Endian
由上可知,采用大小端模式对数据进行存放的主要区别在于存放的字节顺序。通常来讲,Little-Endian最符合人类思维,即将低位值放在内存地址小的地方,将高位值放在内存地址大的地方。而Big-Endian更适合计算机处理。
对于一台机器字节序的判断,有几种方法可以使用:
union NUM { char cval; int ival; } num; num.ival = 0x12345678; if (num.cval == 0x12) printf("It‘s Big-Endian.\n"); else if (num.cval == 0x78) printf("It‘s Little-Endian.\n"); else printf("Cant‘t tell the type of machine.\n");
int ival = 0x1234; char cval = *(char *)&ival; printf("cval = 0x%x\n", cval);
在通用的处理器中,x86体系结构是Little-Endian,而ARM通常采用的是Big-Endian。此外,网络字节序采用的是Big-Endian,它是TCP/IP中规定好的一种数据表示格式,与具体的CPU无关,从而可以保证数据在不同主机之间传输时能够被正确解释。因此在进行网络编程时,通常需要进行大小端字节序的转换。
为了进行字节序的转换,BSD Socket提供了以下4个转换函数:
htons( ) 将unsigned short类型从主机序转换到网络序
htonl( ) 将unsigned long类型从主机序转换到网络序
ntohs( ) 将unsigned short类型从网络序转换到主机序
ntohl( ) 将unsigned long类型从网络序转换到主机序
在使用Little-Endian的系统中,这些函数会把字节序进行转换,而在Big-Endian的系统中,这些函数会定义成宏。
除去大端序和小端序外,还有混合序(Meddle-Endian),它的顺序更为复杂。仍以整型数据0x12345678为例,它在Meddle-Endian系统中的表示为:
0 --> 31
0x34 |
0x12 |
0x78 |
0x56 |
可将这个32bit的数据以16bit分割,前16bit与后16bit以Big-Endian排列;在16bit内部,以Little-Endian排列。这个例子仅作了解。
大端和小端排序是以字节为单位的,但CPU在存储一个字节时,其内部的8个bit之间的排列也有大小端之分。下面以位域(Bit field)为列以作说明。
union { struct { unsigned char c1:2; unsigned char c2:3; unsigned char c3:3; } st; unsigned char ch; } uval; uval.ch = 0x64; printf("c1 = %d\n", uval.st.c1); printf("c2 = %d\n", uval.st.c2); printf("c3 = %d\n", uval.st.c3); return 0;
代码中0x64的二进制为0110 0100,若系统为小端序,其在一个字节内的排序为:
0 --> 7
0 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
程序运行结果显示,c1 = 0,c2 = 1,c3 = 3。即c1取00,c2取100,c3取110。
本例采用的是x86_64和GCC实现。
标签:
原文地址:http://www.cnblogs.com/0xceff/p/4308973.html