蓝点工坊(http://www.bluedrum.cn) 创始人,App和嵌入式产品开发。同时也做相应培训和外包工作。 详细介绍 http://pan.baidu.com/s/1y2g88
全部博文(311)
分类: C/C++
2010-03-24 13:09:27
Andrew Huang
一.整位数字存储
C语言的开发者都知道,32位CPU下,一个整数用4个字节存储的.(即sizeof(unsigned int)==4).一个short型用2字节存储(即sizeof(unsigned short)==2)
那整数在4个byte的内存空间是如何保存的? 首先我们从小学学数学就有一个观念,比如一个整数数字 12345, 数字最高位在最左边,数字最低位在最右边.在C语言编程中也是遵循这样的习惯.比如数字左移,表示数字向左边移动,即低位向高位移动.进位也是由右至左依次进行.在C语言里,把一个数的最高位为MSB(最高有效字节),而一个数的最低位称为LSB(最低有效位).
而计算机的内存是一维的线性空间,是没有左右之分,只有地址高址,低址之分.在32bit CPU下,最低为0x0,最高为0xFFFFFFFF.但是在一般调试软件或者文档之中,如果内存横着描述,一般把低址列左侧,高址位于右侧.如VC++中的描述.
但是我们在Windows 或X86 Linux 测试如下程序.看一下输出结果是
|
程序的输出是 n=0x12345678 (0x78,0x56,0x34,0x12),换句话说,这个数字并不是想象那样,是从低址顺排过来,而且反着排列的.即在内存中是按如下排列的.
为什么会这样呢?这要从CPU的硬件设计说起.CPU的发展过程中,形成了两种流派,一种是数字在内存中是顺排的.即看起来象一般数学表达式,是高字节数据(MSB)存放在低地址处,低字节数据(LSB)存放在高地址处。这种方式叫大端字节序,(big-endian),大部分的嵌入式CPU,象 PowerPC,
另外一种是X86的CPU为代表的,数字在内存中是反排,即低字节数据(LSB)存放在内存低地址处,高字节数据(MSB)存放在内存高地址处,这种方式叫小端字节序,(little-endian),
ARM CPU则可以用软件在启动时设置采用哪一种字节序.但是运行时只能有一种字节序.
两种字节序各有优缺点,大端模式合符人的思维,小端模式合适计算机的处理.效率上并没有差别.只是设计者的喜好.这正好跟这两个术语的来源有一点相似.
端模式(Endian)的这个词出自Jonathan Swift书写的著名童话《格列佛游记》。在这本书里,小人国根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头(较大那头)开始将鸡蛋敲开的人被归为Big Endian,从尖头(较小的那头)开始将鸡蛋敲开的人被归为Littile Endian。大家都觉得自己吃法是最完美的,最后争执不下.最后小人国的爆发了激列的内战,两派人两败俱伤,最后还是归于原状,little-endian仍然从小头开始吃起,big-endian还是从大头吃起.
在CPU的设计上,Endian表示数据在存储器中的存放顺序。对于Big Endian和Little Endian不同的设计也引起了激烈的争论。两者也是各执一词,不过X86占有市场太多,因此Little-Endian略占上风.
|
|
解答:这是一个典形在考你对数字字节序的理解,WIN32暗示你是little endian.又因为union,所以 a,b 共享同一空间。这样b[3]是a的最高2位。因此结果是 0x58
3.在little-endian,下列程序输出结果是多少?
|
解答,这个题可能在没学数字字节序之前,可能都能答对。学了后,反而搞混了,在想little-endian是反排,这样 & 0xFF,应该是取最高位,很容易答成了 0x58,实际上&的操作与数字字节序无关,总是取数字最低一byte.在哪种CPU下,上述答案都是 0x48
三.网络字节序,本机字节序
IP协议是定义在可以在任何操作系统或CPU传输数据的协议。在IP网络传输一个数字,必须用某种方法来解决不同字节序CPU之间解析数字问题,否则在传输时会发混乱.TCP/IP采用一个简单办法,就是统一规定,在IP网络传输数字必须要用指定的数字字节序传输,这个字节序称为网络序(network order).TCP/IP规定网络序采用大端字节序, 相对的, CPU本身数字表示顺序称为本机序(host order)
.
因此在网络编程时,在发送数字之前,比如端口号之类,必须把这些数字本机序转换为网络序.在接收后,也需要把网络序数字转为本机序,这样才能让接收的CPU正常使用数字.
转换的操作是SOCKET定义的标准操作,在支持socket各个操作系统都会要实现如下四个转换函数或宏.
比较明显,如果本机序是big-endian,则上述操作什么都不做,而little-endian则用到移位来操作,比如Linux这个定义在 netinet/in.h 之中,
|
思考:1.这里为什么要强调是unsigned?
2.上述宏 __u32 __x = (x);起到什么作用。
|