字节序byteorder和位序bitorder_第1页
字节序byteorder和位序bitorder_第2页
字节序byteorder和位序bitorder_第3页
字节序byteorder和位序bitorder_第4页
字节序byteorder和位序bitorder_第5页
免费预览已结束,剩余8页可下载查看

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、字节序(byteorder)和位序(bitorder)字节序(byteorder)和位序(bitorder)在网络编程中经常会提到网络字节序和主机序,也就是说当一个对象由多个字节组成的时候需要注意对象的多个字节在内存中的顺序。以前我也基本只了解过字节序,但是有一天当我看到ip.h中对IP头部结构体structiphdr的定义时,我发现其中竟然对一个字节中的8个比特位也区分了大小端,这时我就迷糊了,不是说大小端只有在多个字节之间才会有区分的吗,为什么这里的定义却对一个字节中的比特位也区分大小端呢?下面我们先看一下structiphdr的定义,后文会解惑为什么要在一个字节中区分大小端。struct

2、iphdr#ifdefined(_LITTLE_ENDIAN_BITFIELD)u8ihl:4,version:4;#elifdefined(_BIG_ENDIAN_BITFIELD)_u8version:4,ihl:4;#else#error"Pleasefix"#endifu8tos;_be16tot_len;_be16id;_be16frag_off;_u8ttl;_u8protocol;sum16check;_be32saddr;_be32daddr;/*Theoptionsstarthere.*/);字节序(Byteorder)关于字节序的文章已经有很多了,在我这

3、篇文章中不打算过多的说字节序,但是也不能完全脱离字节序因为后面的重点部分比特序跟字节序也有一定的相似度和联系。字节序就是说一个对象的多个字节在内存中如何排序存放,比如我们要想往一个地址a中写入一个整形数据0x12345678,那么最后在内存中是如何存放这四个字节的呢?0x12这个字节值为最高有效字节,也就是整数值的最高位(在本文中0x12=0x12000000),0x78为最低有效字节。图1:大端字节序上图是大端字节序的示意图,所谓"大端字节序”,便是指最高有效字节落在低地址上的字节存放方式。图2:小端字节序而小端字节序就是最低有效字节落在低地址上的字节存放方式。0x12345678

4、=0x12000000+0x340000+0x5600+0x78,所以要想保持一个对象的值在大小端系统之间不变,那么就必须确保不同的系统能够正确的识别最高有效字节和最低有效字节(不能错误的识别最高、最低有效字节)。同样的字节序12345678在大端序机器中会识别为0x12345678(0x12000000+0x340000+0x5600+0x78=0x12345678),在小端序机器中识别为0x78563412(0x12+0x3400+0x560000+0x78000000=0x78563412)。所以要想两者保持一致就必须确保系统能够正确的识别最高有效字节0x12和最低有效字节0x78,那么

5、在小端系统中字节存放的顺序应该为78563412。比特序(bitorder)字节序是一个对象中的多个字节之间的顺序问题,比特序就是一个字节中的8个比特位(bit)之间的顺序问题。一般情况下系统的比特序和字节序是保持一致的。一个字节由8个bit组成,这8个bit也存在如何排序的情况,跟字节序类似的有最高有效比特位、最低有效比特位。比特序10010010在大端系统中最高有效比特位为1、最低有效比特位为0,字节的值为0x92。在小端系统中最高、最低有效比特位则相反为0、1,字节的值为0x49。跟字节序类似,要想保持一个字节值不变那么就要使系统能正确的识别最高、最低有效比特位。字节序转换函数ntohl

6、(s)、htonl(s)在socket编程中经常要用到网络字节序转换函数ntohl、htonl来进行主机序和网络序(大端序)的转换,在主机序为小端的系统中字节序列78563412(val=0x12345678)经过htonl转换后字节序列变成12345678:图3:htonl函数字节序转换后我在想是不是比特序也一同进行了转换?为什么会有这个疑问呢,因为前文可知系统的比特序和字节序是一致的,现在字节序已经从小端变成了大端那么比特序应该也要一起转换。而且如果比特序不变化那么当这些字节到了目标大端序系统中后每一个字节的值都会发生变化,因为同样的比特序列在小端和大端系统中识别的字节值会不一样。首先从h

7、tonl、ntohl的源码来看确实只进行了字节序的转换并没有进行比特序的转换,再有就是以前socket编程的时候只调用了ntohl、htonl等函数并没有调用(而且系统也没有提供)比特序转换函数,但是最后的结果都是正确的,并没有发现上面提到的字节值发生变化的问题。那么这个“神奇”的事情是怎么解决的呢,好像系统本身就给我们“悄悄”的解决了我担心的问题。答案我们下文揭晓。比特(bit)的发送和接收顺序比特的发送、接收顺序是指一个字节中的bit在网络电缆中是如何发送、接收的。在以太网(Ethernet)中,是从最低有效比特位到最高有效比特位的发送顺序,也就是最低有效比特位首先发送,参考资料:fram

8、e。在以太网中这个规定有点奇怪,因为字节序我们是按照大端序来发送,但是比特序却是按照小端序的方式来发送,下图是直接从网上找来的一张图,主机序本身是大端序:图4:比特发送、接受示意图比特的发送、接收顺序对CPU、软件都是不可见的,因为我们的网卡会给我们处理这种转换,在发送的时候按照小端序发送比特位,在接收的时候会把接收到的比特序转换成主机的比特序,下面是一个小端机器发送一个int整型给一个大端机器的示意图:图5:小端,大端比特发送示例因为对网卡对比特序的发送、接收所做的转换没有深入的了解所以上图很有可能会有错误之处。现在来回答一下第3节中的那个疑问:htonl、ntohl函数肯定是不会同步转换一

9、个字节中的比特序的,因为如果比特序也发生了转换的话那么这个字节的值也就发生了变化,记住htonl、ntohl只是字节序转换函数。比特序按照小端的方式发送,首先发送的是最低有效比特位,最后发送的是最高有效比特位,接收端的网卡在接收到比特序列后按照主机的比特序把接收到的“小端序”比特流转换成主机对应的比特序列。可以假设存在ntohb、htonb(b代表b©这样的两个函数,网卡进行了比特序的转换,不过是这两个函数是网卡自动调用的,我们平时不用关注。按照规则,发送、接收的时候进行比特序的转换,那么就能保证在不同的机器之间进行通信不会发生我担心的字节值发生变化的问题。结构体的位域关于C语言中结

10、构体的位域可以参考这篇文章:对于位域有一个约定:在C语言的结构体中如果包含了位域,如果位域A定义在位域B之前,那么位域A总是由现在低序的比特位。在计算机中可寻址的最小单位为字节,bit是无法寻址的,但是为了抽象我们可以把计算机的最小寻址单位变成bit,也就是我们可以单独获得一个bit位。我们有如下的一段代码:#includestructbit_orderunsignedchara:2,b: 3,c: 3;intmain(intargc,char*argv)unsignedcharch=0x79;structbit_order*ptr=(structbit_order*)&ch;prin

11、tf("bit_order->a:%un",ptr->a);printf("bit_order->b:%un",ptr->b);printf("bit_order->c:%un",ptr->c);return0;)我们把代码在gentoo(intel小端机器)、hu-unix(大端机器)两个机器上面编译、运行,结果如下:liuxingenV6-Dev/station$./bitfiledbit_order->a:1bit_order->b:6bit_order->c:3下面是hp-

12、unix的运行结果#./bitfiledbit_order->a:1bitorder->b:7bitorder->c:1我们先分析一下gentoo上面的结果:图6:小端机器的位域示例从上图中我们很容易就能理解gentoo上面的输生结果,下面是hp-unix上面示意图:图7:大端机器的位域示例从上面的输生可以看到同样的代码在不同的机器中输生了不同的结果,也就是说我们的代码在不同的平台不能直接移植,导致这个问题的原因就是我们前面提到的关于位域的一个约定,定义在前面的位域总是由现在低地址的bit位中,因为不同的平台的比特序是不同的,但是我们定义的位域没有根据平台的大小端进行转换,最

13、后就导致了问题。那么如何解决这个问题,那就是在定义结构体中的位域时判断平台的大小端:#include#includestructbit_order#ifdefined(_LITTLE_ENDIAN_BITFIELD)unsignedchara:2,b: 3,c: 3;#elifdefined(_BIG_ENDIAN_BITFIELD)unsignedcharc:3,b:3,a:2;#else#error"Pleasefix"#endif;intmain(intargc,char*argv)unsignedcharch=0x79;structbit_order*ptr=(structbit_order*)&ch;printf("bit_order->a:%un"

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论