浅谈数据存储之大端法和小端法

来源:互联网 发布:switch case用法 java 编辑:程序博客网 时间:2024/05/01 13:24

说到大端法和小端法,就不得不提到数据在计算机内部的存储。首先,大多数计算机是使用一个字节作为可寻址的最小存储单位,也就是说,一个内存地址指向的存储空间的容量是一个字节,而我们可以把整个计算机的内存抽象为一个非常大的字节数组,数组的每一个元素占一个字节,并且都可以用唯一的数字来标识,这些数字即是我们平常说的内存地址。

如果说要存储的对象都是一个字节,那么用数组的一个元素就能存储,但假如要存储的对象大于一个字节,那么这个时候有两个问题需要回答,第一个问题是:对于多字节的对象,它的地址是多少?第二个问题是:对于多字节的对象,它们在内存中是怎样存储的?

对于上面两个问题,首先,多字节对象的存储地址为它所使用字节中的最小地址。此外,多字节对象在内存中都被存储为连续的字节序列,即多字节对象在内存中是连续存储的。举个例子,比如说一个int类型的变量a的地址为0x100,那么它在内存中所占的字节的地址为0x100,0x101,0x102,0x103。

由上面提到的多字节对象连续存储的问题,从而引出了本文开篇提到的大端法和小端法。它们表示了连续存储的多字节对象的存储规则。举个例子,现在有一个w位的整数,用位的方式表示为:[xw-1, xw-2, …, x1,x0],其中xw-1为最高有效位,x0为最低有效位。假设w为8的倍数,这些位就能被表示为字节(1 byte = 8 bit),其中[xw-1, xw-2, … , xw-8]为最高有效字节,而[x7,x6, … , x0]为最低有效字节。有些机器选择在内存中按从最低有效字节到最高有效字节的顺序存储多字节对象,这样的方式我们称之为小端法;相反,有的机器选择在内存中按从最高有效字节到最低有效字节的顺序存储多字节对象,这样的方式我们称之为大端法。举个例子,一个int类型的变量,其值的十六进制表示为0x01234567,地址范围是0x100到0x103,如果所在机器采用大端法,那么表示方式如图一,如果所在机器采用小端法,那么表示方式如图二。

 

讲到这里,读者或许会问,大端法和小端法这个东西有什么意义呢?这里讲两点。第一点,当利用网络传输数据时,如果数据发送方所在机器用的是小端法(大端法),而数据接收方所在机器用的是大端法(小端法),那么这个时候数据接收方接收到的表示数据的字节序列就是反序的。所以在进行网络编程时,需要考虑到不同机器的兼容性。第二点,有的时候我们会去阅读机器级的代码,而这个时候知道所在机器所使用的是大端法还是小端法就至关重要了,因为这影响着我们对于机器级代码阅读的正确性。比如现在有一行机器级代码,它表示一个地址:64 94 04 08,如果该机器使用大端法,那么该地址应该是0x64940408,如果该机器使用小端法,那么该地址应该是0x08049464。由此可见,了解一台机器使用的是大端法还是小端法,对于阅读由它生成的机器级代码是很有帮助的。

最后,通过对一个问题的分析来总结全文。这个问题是:如何确定一台机器使用的是大端法还是小端法呢?

首先,这个问题可以通过下面的C程序来解决。

 


 

         程序在第5行定义了一个int类型变量,为了便于下面的解释,这里将其值用十六进制表示。注意,这个值和我们上面举的例子用的是同一个值。

         这里重点解释一下第6行代码。首先,&a表示变量a的地址,这个地址所标识的存储空间存放的是一个int类型的值,而我们知道地址和指针是等价的,因此,&a也可以看成是一个指向int类型的指针,它指向了整个这个int类型对象(如图三),即0x01234567,而该对象是由一个包含4个字节的字节序列构成的,即01, 23, 45, 67。(char*)&a所做的工作是一个强制类型转换,将int*强制转换成char*并赋值给cptr,由于char类型占一个字节,这样一来,指针cptr就会被看作指向了表示这个int对象的字节数组(如图四),而对于一个连续存储的字节数组,cptr指向字节数组的第一个元素,并且第一个元素所在的地址为数组所占的字节的最低地址。

         程序在第7行计算了cptr指向的字节数组的长度,由于int类型占4个字节,因此byte_len的值为4。

         程序在第8行至第11行的for循环中按照字节数组在内存中存储的顺序输出这个字节数组的元素。输出的结果为67, 45, 23, 01。说明我的机器采用的是小端法。

 

 

0 0