ImageVerifierCode 换一换
格式:DOCX , 页数:25 ,大小:42.23KB ,
资源ID:509478      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-509478.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(不同架构的字节顺序释疑.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

不同架构的字节顺序释疑.docx

1、不同架构的字节顺序释疑交换字节在计算领域存在两种不同的字节顺序处理方法(或者说是endian格式)。endian格式指定了如何在内存中存储多字节数值中的各个字节;Big-endian的字节顺序处理方式表示存储多字节数据的时候权重最大的字节放在前面。Little-endian的字节顺序处理方式则表示存储多字节数据的时候权重最小的字节放在前面。PowerPC处理器使用big-endian的字节顺序处理方式,x86 处理器家族则使用little-endian的字节顺序处理方式。根据约定,多字节的数据在网络上发送的时候,使用big-endian的字节处理方式。如果您的应用程序假定数据是某种endian

2、格式,而实际上数据使用的是另一种格式,则程序就会不正确地解析数据。您需要对代码中负责从磁盘或者网络读取多字节的数据(16位,32位,或者64位),或者将多字节数据写入到磁盘或网络的例程进行分析,因为这些例程对于字节顺序格式相当敏感。有两个常见的处理字节顺序差别的方法:在必要的时候进行字节交换,或者使用XML或其它与字节顺序无关的数据格式,比如Core Foundation框架中的格式(CFPreferences,CFPropertyList,CFXMLParser)。采用字节交换的方法,还是使用与字节顺序无关的数据格式存储数据,取决于您在应用程序中如何使用数据。如果您需要支持某个现有的文件格式

3、,则二进制兼容的解决方案是首先接受应用程序中已经在使用的big-endian文件格式,然后书写字节交换代码,在x86系统上读写文件时使用。如果不需要支持老的文件,则可以考虑重新设计文件格式,以使用XML(extended markup language,即扩展的标志语言),XDR(external data representation,即外部数据表示),或者NSCoding(Objective C)来表示数据。本章接下来的部分将描述为什么字节顺序会带来问题,给出交换字节的指导原则,描述Mac OS X中提供的字节交换API,并且对大多数与字节顺序有关的情况提供解决方案。本部分包括如下主要内容

4、:为什么字节顺序会带来问题交换字节的指导原则字节交换例程字节交换策略为字节交换数据书写和安装一个回调函数相关信息为什么字节顺序会带来问题这个部分的例子的设计目的是更为详尽地向您展示字节顺序为什么会带来问题。请看一下列表3-1中定义的C语言的数据结构。它包含一个四个字节的整形数,一个字符串,以及一个双字节的整形数。列表中的代码还初始化了这个结构。列表3-1 :包含多字节和单字节的数据结构typedef struct uint32_t myOptions; char myStringArray 7; short myVariable; myDataStructure;myDataStructure

5、 aStruct; aStruct.myOptions = 0xfeedface; strcpy(aStruct.myStringArray, safari); aStruct.myVariable = 0x1234;请对比一下(参见图 3-1)在big-endian和little-endian系统上是如何将这个结构存储在内存中的。在big-endian系统中,每个数据字节在内存中的地址是随着各个字节的权重从大到小递增;而在little-endian系统中,每个数据字节在内存中的地址是随着各个字节的权重从小到大递增。图 3-1 :Big-endian系统和little-endian系统的的字节

6、组织顺序对比在您查看图3-1时,请注意下面几点: 多字节数据,比如图中显示的32位和6位长的变量,在big-endian和little-endian系统中存储方式是不一样的。在图中您可以看到,big-endian 系统在存储数据时将权重最大的字节存放在最低的内存地址上,Little-endian系统在存储数据时则将权重最大的字节存放在最高的内存地址上。因此,在big-endian系统上,myOptions变量(0xce)权重最小的字节被存放在地址为0x00000003的内存单元上,而在little-endian 系统上则存放在地址为0x00000000的内存单元上。 单字节数据,比如myStr

7、ingArray字符数组中的char值,在两种系统中都存在同一个内存位置上,无论其字节顺序格式是什么。 每个系统都进行字节填充,以保持4字节数据是对齐的。在图中,填充字节用包含星号(*)的带阴影的方框来表示。如果您希望在使用某个架构的系统上读取数据,而该数据是在使用不同架构的系统中写入的,并且您需要按字节访问数据,则多字节数据在内存中的字节顺序就会带来影响。举例来说,如果您的应用程序需要访问myOptions变量的第二个字节,则当您从采用反向字节顺序的系统中读取数据的时候,结果就会得到myOptions变量的第一个字节,而不是第二个字节。假定由列表 3-1的代码初始化过的实例数据是在一个lit

8、tle-endian系统中生成,并存储到磁盘上,而且该数据是按照字节地址的顺序写入磁盘的,数据在内存中的排列状态就如图 3-1所示。问题在于,即使在一个big-endian系统中解析这些数据进行解析,其字节顺序仍然是little-endian格式的。这个差别会导致求值不正确。在这个例子中,myOptions变量的值应该是0xfeedface,但是因为不正确的字节排列顺序,这个变量的求值结果为0xcefaedfe。请注意:big-endian和little-endian这两个术语来自Jonathan Swift在十八世纪的嘲讽作品Gullivers Travels。 Blefuscu帝国的国民被

9、根据吃鸡蛋的方式划分为两个部分:一部分在吃鸡蛋的时候从鸡蛋的大端(big end)开始,而另一部分则从鸡蛋的小端(little end)开始。交换字节的指导原则下面的指导原则和本章梢后提供的策略可以帮助您确定程序中的字节交换代码是否合适。 在内存中,以本地的字节顺序保存数据。只在从磁盘读取数据或者将数据写入磁盘的时候进行字节交换。 在可能的情况下,让编译器为您实现这些工作。举例来说,当您使用诸如Core Foundation中的CFSwapInt16BigToHost这样的函数时,编译器会确定该函数是否为您的目标处理器做过处理。如果该代码什么都没有做,则不会被调用。让编译器实现这个工作,比您自

10、行使用#ifdef语句进行控制要更加有效。 如果您必须访问一个大的文件,则请考虑将数据以某种方式进行排列,以减少您必须进行的字节交换操作。举例来说,您可以将最经常被访问的数据连续地排列在文件中。这样,您只需要读取一块数据,并对之进行字节交换,而不用操作整个数据文件。 只有在必须的时候,才使用_BIG_ENDIAN_和_LITTLE_ENDIAN_宏。不要使用检查特定处理器类型的宏,比如_i386_和_ppc_。 选择一个持续的字节顺序方法,并坚持使用这个方法。也就是说,如果您按照一定的规则从磁盘读取数据或者向磁盘写入数据,请选择您希望使用的endian格式。这样可以减少检查数据字节顺序的必要,

11、从而减少可能的字节顺序交换。 记住哪些函数返回big-endian的数据,并正确处理该数据。这类函数包括DNSServiceDiscovery函数(端口是网络字节顺序),以及ColorSync描述函数(所有数据都是big-endian)。 IconFamilyElement 和IconFamilyResource 数据类型(也包括IconFamilyPtr和IconFamilyHandle类型)总是big-endian格式的。可能有一些其它的函数和数据类型没有列举在这里,请从相应的API参考资料中查找函数的返回数据信息。 请记住,字节交换会带来性能上的开销,因此只在有必要的时候交换字节。字节交

12、换例程下面列举了提供字节交换例程的API。绝大多数情况下,最好使用与您的编程框架相匹配的例程。在下面列举的API中,Core Foundation和Foundation API提供了浮点数值字节交换例程,其它API则没有。 POSIX (Portable Operating System Interface,即可移植的操作系统接口)中的字节顺序处理函数(ntohl,htonl,ntohs,和htons)在man页面中有所描述,可以在Terminal或者Xcode中查看。 Darwin字节顺序处理函数和宏在头文件中定义。虽然这个头文件是在libkern中定义的,但是在高级别的应用程序中使用也是可

13、以接受的。 Core Foundation的字节顺序处理函数在头文件中定义,其描述信息位于字节顺序工具参考部分。如果需要如何使用这些函数的详细信息,请参见内存管理一文中的字节交换部分。 Foundation的字节顺序处理函数在头文件中定义,其描述信息位于Objective C的Foundation参考部分。 Core Endian API在头文件中定义。这个头文件中的字节交换函数在QuickTime参考文档中进行描述。这个API中的函数名称都以Endian作为前缀。您可以通过QuickTime参考中的函数的字母索引 部分找到这些函数的描述信息。请注意:在您使用字节交换例程的时候,编译器会对您的

14、代码进行优化,以使这些例程只在代码运行所在的架构需要的时候才被执行。字节交换策略交换字节的策略取决于数据的格式,不存在可以处理所有字节顺序差别的通用例程。单字节的字符串完全不需要交换,32位的数量型需要对四个字节进行颠倒交换,16位的数量型则需要在两个字节之间进行颠倒交换。任何需要交换数据的程序都必须知道相应数据的类型,源数据的endian顺序,以及当前宿主系统的endian顺序。本部分针对下面这些数据类型列出了各种字节交换的策略,内容上按照字母顺序进行组织: “常数” “定制的苹果事件数据” “定制的资源数据” “浮点数” “整型数” “网络相关的数据” “OSType-to-String的

15、转换” “Unicode文本文件”常数常数作为编译完成的执行文件的一部分,其字节顺序是宿主系统的字节顺序。只有当常数成了不在本地维护的数据的一部分,或者需要在不同的宿主系统之间进行转移,才需要进行字节交换。在大多数的情况下,您可以在前期进行字节交换,或者通过移位或其它简单的操作符,让预处理器进行必要的数学运算。如果您定义和使用的结构必须以某种特定的endian格式存在于内存中,则可以使用libkern/OSByteOrder.h头文件定义的OSSwapConst宏和OSSwap*Const变量来进行处理。这些宏可以在高级别的应用程序中使用。定制的苹果事件数据苹果事件(Apple Event)是

16、一种遵循苹果事件进程间消息传递协议(Apple Event Interprocess Messaging Protocol)的高级事件。苹果事件管理器(Apple Event Manager)负责在同一个电脑的应用程序,或者在远程电脑上的应用程序之间发送苹果事件。您也可以定义自己的苹果事件数据类型,然后通过苹果事件管理器的API发送和接收苹果事件。Mac OS X会为您管理系统定义的苹果事件数据类型,并为当前正在执行的代码正确地处理这些类型。您不需要执行任何特殊的任务。当您的应用程序从苹果事件抽取系统定义的数据时,系统会在向您的应用程序发送事件之前,将数据进行字节交换。您需要按照本地的endi

17、an格式来解析苹果事件中的系统定义数据类型。类似地,如果您将一个本地endian格式的数据放在一个即将发送的苹果事件中,而且该数据是系统定义的数据类型,则接收方也能够以其本地endian格式解析这个数据。然而,对于您自行定义的定制苹果事件,必须考虑字节顺序的差异。通过下面的任何一种方法都可以完成这个工作: 书写字节交换回调函数(也称为flipper),并提供给系统。每当系统确定您的苹果事件需要进行字节交换的时候,就激活您的flipper程序,以确保数据的接收方能够收到正确endian格式的数据。如果需要细节信息,请参见“书写和安装字节交换数据的回调函数”。 不管具体的架构是什么,选用一种的en

18、dian格式。这样,在读写定制的苹果事件数据的时候,就可以使用big-to-host和host-to-big例程,比如Core Foundation的字节顺序工具(Byte Order Utilities)中的CFSwapInt16BigToHost和CFSwapInt16HostToBig函数。定制的资源数据在Mac OS X上推荐的提供资源的方法是在应用程序包中提供一些文件,来定义诸如图像文件,声音,本地化文本,以及归档的用户界面这样的资源。而本文的这个部分讨论的资源数据是指Carbon支持的资源管理器风格(Resource Manager-style)的资源文件中定义的资源。资源管理器在

19、Mac OS X之前就已经推出了。如果您的应用程序使用了资源管理器风格的资源文件,则应该考虑将它们向应用程序包中的Mac OS X风格的资源转换。资源通常包含描述菜单,窗口,控件,对话框,声音,字体,和图标数据。系统定义了很多标准的资源类型(比如movv,用于指定一个QuickTime电影,还有MENU,用于定义菜单),您可以创建自己的私有资源类型,在自己的应用程序中使用。通过资源管理器的API,您可以定义资源数据类型,以及获取和设置资源数据。Mac OS X在内存中跟踪资源,使您的应用程序可以读写资源。应用程序和系统软件根据资源的类型为资源解析数据。虽然在通常情况下,您会让操作系统自行读取资

20、源(比如应用程序图标),但是您也可以直接调用资源管理器函数来读写资源。Mac OS X为您管理系统定义的资源,并为当前正在运行的代码正确地处理这些资源。也就是说,如果您的应用程序运行在一个x86系统上,则Mac OS X会进行相应的字节交换,使应用程序的图标,菜单,以及其它标准资源正确显示。您不需要任何特殊的工作。但是如果您为自己的应用程序定义了私有的资源,则从磁盘读或者向磁盘写资源的时候需要考虑不同架构之间的字节顺序差异。您可以使用下面的策略来处理资源管理器风格的定制资源数据。请注意,这些策略和用于处理定制苹果事件数据的策略是相同的: 为系统提供一个字节交换回调函数。每当系统确定您的资源数据

21、必须进行字节交换的时候,就调用该函数。如果需要细节信息,请参见“书写和安装字节交换数据的回调函数”。 不管具体架构是什么,总是使用同样的endian 格式来写数据。这样,在读写您自己定制的资源数据的时候,就可以使用big-to-host和host-to-big例程,比如Core Foundation的字节顺序工具(Byte Order Utilities)中的CFSwapInt16BigToHost和CFSwapInt16HostToBig函数。请注意:如果您正在修改采用预装载位(preload bit)标识资源的代码,则应该将预装载位从所有需要经过字节交换处理的资源中删除。 在Mac OS

22、X中,预装载位几乎总是没有必要的。如果不能删除预装载位,则应该在资源读取完成之后才对资源数据进行字节交换。您不能用flipper回调函数来自动进行字节交换,因为在Mac OS X上,预装载位会导致资源在运行任何应用程序代码之前,首先被读取。浮点数Core Foundation定义了一套函数以及两个特殊的数据类型来帮助您处理浮点数。这些函数使您可以用某种方式对32位和64位的浮点数进行编码,从而使您可以在必要的时候进行解码和字节交换。列表3-2向您说明如何对64位的浮点数进行编码,而列表 3-3说明如何解码。列表3-2 :对一个浮点数进行编码Float64 myFloat64;CFSwapped

23、Float64 swappedFloat;/ Encode the floating-point value.swappedFloat = CFConvertFloat64HostToSwapped(myFloat64);CFSwappedFloat32和CFSwappedFloat64数据类型将浮点数包含在一个规范表示中。CFSwappedFloat 数据类型本身不是一个浮点数,不应该直接被使用。然而您可以将它发送给另一个进程,将它存储在磁盘,或者通过网络进行发送。由于该格式可以通过转换函数和规范格式进行相互转换,因此不需要显式地进行处理字节交换问题。如果需要的话,在格式转换的过程中就会自动

24、处理这个问题。列表3-3 :对一个浮点数进行解码Float64 myFloat64;CFSwappedFloat64 swappedFloat;/ Decode the floating-point value.myFloat64 = CFConvertFloat64SwappedToHost(swappedFloat);NSByteOrder.h头文件中也定义了一些函数,与这里讨论的Core Foundation定义的函数相类似。整型数系统库中的字节访问函数,比如OSReadLittleInt16和OSWriteLittleInt16,提供了基本的字节交换功能。如果本地的endian格式和目

25、标的endian格式不同,这些函数就进行字节交换。它们在libkern/OSByteOrder.h头文件中定义。请注意:OSReadXXX和OSWriteXXX类型函数要比OSSwapXXX类型的函数或者其它较为高级的框架中的函数性能好。Core Foundation为字节交换提供了三个优化过的基本函数CFSwapInt16,CFSwapInt32,和CFSwapInt64。所有其它的字节交换函数都使用这三个基本函数来完成它们的工作。一般地说,您不必直接使用这些基本函数。基本的字节交换函数是无条件地进行交换,更高级别的交换函数则不同,它们以下面的方式来进行工作:当字节不需要交换的时候换句话说,

26、当源和宿主系统的字节顺序相同的时候,函数什么都不做。对于整形数类型,这些函数的形式是CFSwapXXXBigToHost和CFSwapXXXLittleToHost,CFSwapXXXHostToBig,和CFSwapXXXHostToLittle,其中XXX是数据类型,比如Int32。举例来说,在一个little-endian的机器上,您可以用CFSwapInt16BigToHost函数来从网络上读取一个16位的整数,网络上数据的字节顺序是网络字节顺序(big-endian)。列表 3-4演示这个过程。列表3-4 :将一个16位的整数从big-endian转换为主机系统的endian格式SI

27、nt16 bigEndian16;SInt16 swapped16;/ Swap a 16-bit value read from the network.swapped16 = CFSwapInt16BigToHost(bigEndian16);假定整形数是一个数据结构中的成员,列表3-5 中演示如何完成相应的字节交换。列表3-5 :将一个整数从little-endian转换为主机系统的endian格式/ Byte swap the values if necessary.aStruct.int1 = CFSwapInt32LittleToHost(aStruct.int1)aStruct.

28、int2 = CFSwapInt32LittleToHost(aStruct.int2)字节交换代码只有在必要的时候才交换字节。如果宿主系统是big-endian架构,则例子代码中使用的函数就会对每个成员进行字节交换;而当代码运行在little-endian的机器上时,字节交换代码则什么都不做编译器对代码进行了优化。网络相关的数据与网络相关的数据(IP地址,端口号,等等)通常使用big-endian格式(也称为网络字节顺序),因此在网络和x86系统之间进行通讯的时候,您可能需要进行字节交换。在向网络传递数据,或者从网络接收数据的时候,您可能永远都不需要调整PowerPC代码。在x86系统上,您

29、则必须仔细查看网络通讯代码,确保自己总是以正确的字节顺序发送与网络有关的数据。您还必须正确处理从网络上接收的数据,将数值通过字节交换处理为适合于宿主系统的微处理器的endian格式。您可以使用下面这些POSIX函数来在网络字节顺序和宿主系统的字节顺序之间进行转换(其它字节交换函数,比如OSByteOrder.h和CFByteOrder.h头文件中定义的那些函数,也可以用于处理网络数据)。 网络到宿主系统:uint32_t ntohl (uint32_t netlong);uint16_t ntohs (uint16_t netshort); 宿主系统到网络:uint32_t htonl (ui

30、nt32_t hostlong);uint16_t htons (uint16_t hostshort);这些函数的信息技术在man页面中,可以在Terminal或者Xcode查看。sockaddr_in结构中的sin_saddr.s_addr和sin_port成员的字节顺序应该总是网络字节顺序。通过阅读man页面文档,您可以找出适合于BSD网络通讯函数的每个参数的endian格式。OSType-to-String的转换您可以使用 UTCreateStringForOSType 和 UTGetOSTypeFromString 函数来在类型为OSType的值和CFString对象(CFStrin

31、gRef数据类型)之间相互转换。这些函数在统一类型标识符概述一文中讨论,它们的定义位于UTType.h头文件中,该头文件是Launch Services框架的一部分。当您使用四字符的标识符时,请记住“abcd” != abcd,而应该是abcd = 0x61626364。您必须将abcd当作一个整形数,而不是字符串数据,因为abcd是一个32位整数的便利方式(一个FourCharCode数据类型就是一个UInt32数据类型)。编译器并不自动进行字节交换。如果您需要处理每个单独的字符,则可以使用移位操作符。举例来说,如果您现在用标准的C printf风格的语法打印一个OSType或者FourCharCode 类型的值,则请用下面的方式:printf(%c%c%c%c, (char) (val 24), (char) (val 16), (char) (val 8), (char) val)而不要用下面这种方式:

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2