字节序(Big-Endian/Little-Endian)

(注:参考了http://bbs.ednchina.com/BLOG_ARTICLE_194674.HTM,

http://www.bozhiw.com/doc-view-4480.html,

http://www.360doc.com/content/13/0320/19/1317564_272753026.shtml博客中的内容)

Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu  转载请标明来源 

 

 

1. Endian来源,故事看起来很有意思

“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

 

2. Little-Endian/Big-Endian解释

Little-Endian: 字节序低位在前  小尾 在操作系统上很常用,也是计算机系统上最常用的字节序

Big-Endian:    字节序高位在前 大尾  也称为网络字节序

16进制数字0x12345678,little-endian的存储为:  0x78 0x56 0x34 0x12     地址依次为100, 101, 102, 103

16进制数字0x12345678,big-endian的存储为:   0x12 0x34 0x56 0x78     地址依次为100, 101, 102, 103

 

3. 用途

Little-Endian最常用,大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian的。

Big-Endian最常用在网络协议上,例如TCP/IP协议使用的是big endian. 操作系统上如MAC OS ,是Big Endian 的。

本质上说,Little Endian还是Big Endian与操作系统和芯片类型都有关系。PowerPC系列采用big endian方式存储数据,x86系列则采用little endian方式存储数据。

 

4. 编程上

C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的。

而JAVA编写的程序则唯一采用big endian方式来存储数据。

注意:字节序是指  多字节数据 在计算机内存中存储或者网络传输时各字节的存储顺序。
   像char/byte型不受字节序影响的,因为他们本身就是单字节数据类型
   像w_char, int, short, long, double等多字节类型,是要受字节序影响的。

 

 

5. 下面的是演习的例子

我在自己的PC机上测试,PC机,通常都是little-endian的

	unsigned int uiTemp = 0x12345678;
	char *pcTemp = (char*)(&uiTemp);
	printf("pcTemp = %x %x %x %x\n", *pcTemp, *(pcTemp+1), *(pcTemp+2), *(pcTemp+3));

这段代码的输出为:pcTemp = 78 56 34 12
猜测一下,如果是Big-endian的话,输出的应该为 pcTemp = 12 34 56 78

(再来附一个链接地址,地址里也是一个例子,里面介绍的也是字节序、截取、还包括高位填充):http://www.cnblogs.com/ideaseek/archive/2010/07/29/1787755.html)

 

5. 如何判断高位当前CPU是Big-Endian还是 Little-Indian

利用union来判断字节序:联合中的数据成员是共享存储空间的,所分配的空间为数据成员中最大所需的内存数。union 的成员本身就被存放在相同的内存空间(共享内存,正是union 发挥作用的地方)。

参考Linux源码中的判断方法 :

char c[4]是数组,空间是顺序进行存储的,1001('1'), 1002('?'), 1003('?'), 1004('b)

unsigned long型的数字也使用这个空间后,存储的信息肯定是不变的。

变的是:当为little-endian时,1001('1')地址存储long型低位的值

                当为big-endian时,1003('b')地址存储long型低位的值

unsigned long转char型时,把long型的低位的值传递给char型。

// 类型转换是在寄存器中处理的,不受字节顺序干扰,字节多的向字节少的转时,把低位的值截断并转出

static union {char c[4]; unsigned long l;} endian_test = {'1', '?', '?', 'b'};
#define ENDIANNESS ((char)endian_test.l)
if ('1' == ENDIANNESS)
{
     printf("little-endian\n");
}
else
{
    printf("big-endian\n");
}

 

6. 字节序与指针

我们都知道指针是4个字节,指针的内容存储的是一个地址:指针取值(dereference)时,根据指向类型的不同,提取不同长存的存储空间中的数据,获取到指向的值。

int iTemp = 0x12345678    // 假设iTemp存储使用的字节地址范围是 100,101,102,103

int *pInt = iTemp;                  // 指针指向地址 100

char *pChar = iTemp;         // 指针指向地址  100

我们之前已知了:

16进制数字0x12345678,little-endian的存储为:  0x78 0x56 0x34 0x12     地址依次为100, 101, 102, 103

16进制数字0x12345678,big-endian的存储为:   0x12 0x34 0x56 0x78     地址依次为100, 101, 102, 103

好了,这下我们知道*pInt肯定是不变的,值不受字节序干扰(字节序变了,识的次序也变,负负得正),还是不会变,值为0x12345678

*pChar受影晌的就大了,它的值仅有一个存储空间,只取出一个存储空间的值,100地址的值。little-endian时,值为0x78; big-endian时,值为0x12

// 也因此,我们可以据pChar的值为0x12还是0x78来判断字节序是高字节,还是低字节

 

 

你可能感兴趣的:(字节序)