字节序(byte order)和位序(bit order)

合集下载

通讯协议之——字节序

通讯协议之——字节序

通讯协议之——字节序最近有接触通讯协议有碰到字节序,记得上学的时候有说过不过太久了不怎么记得了,现在我在这⾥说说字节序;我们都知道计算机存储数据的时候都是把数据转换成字节进⾏存储,⽽⽇常我们的程序或存储的数据通常都是由多个字节组成的,⽽不同的计算机或设备存储的规则⼜不⼀致,导致我们在多计算机、设备间传输数据时就要了解设备的字节存储(字节序)规则是怎样的,这就是我们要了解字节序的原因,在做⽹络编程,游戏编程时这是必须清楚的知识;⽐如:在我们使⽤的计算机编程语⾔中就有各种数据类型:byte,int,short,long等等⽽a byte由⼋个bit组成,⼀个short由两个字节组成,⼀个int由四个字节组成等,⽽我们对byte、short、int等这些数据进⾏存储或通过⽹络传输时需要把他转换为byte进⾏存储或传输,这时把⼀个int转为byte数组时的数据存储顺序就成为:字节顺序。

例如: int 类型数据:33818120,对应的⼗六进制为:0x02040608转成byte数组后byte数据为:byte[4]= {02,04,06,08}byte数组中的数据的顺序就称为:字节顺序为什么在存储或⽹络编程的时候要关注字节顺序呢?在⽹络编程中⽐如我们发送的数据为:byte[4]= {02,04,06,08}⽽接收端不清楚我们的字节顺序⽽使⽤与我们相反的字节顺序接收数据:byte[4]= {08,06,04,02}这就导致接收端收到的数据变成了错误⽆效的数据,我们发送的数据为:33818120,⽽现在由于他不知道我们的字节顺序导致接收到的数据为:134611970;在英⽂上这个词为endian,有翻译为端序、字节序等等,我这⾥称为【字节序】,据说endian这个词的由来源⾃18世纪的⼀本⼩说《格列佛游记》,⼩说中:“吃鸡蛋时是从鸡蛋较⼤的⼀端打破鸡蛋还是从鸡蛋较⼩的⼀端打”,还以为这事有了叛乱;1980年⼀个⽹络协议的开发者在其著名的论⽂《On Holy Wars and a Plea for Peace》中⾸次使⽤了该词。

字节序(byteorder)和位序(bitorder)

字节序(byteorder)和位序(bitorder)
unsigned char ch = 0x79; struct bit_order *ptr = (struct bit_order *)&ch;
printf("bit_order->a : %u\n", ptr->a); printf("bit_order->b : %u\n", ptr->b); printf("bit_order->c : %u\n", ptr->c);
gentoo
6 gentoo
hp-unix
7 bit
#include<stdio.h> #include<asm/byteorder.h>
struct bit_order{ #if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned char a: 2, b: 3, c: 3;
1. (Byte order)
0x12
a 0x12345678 ( 0x12=0x12000000) 0x78
1 ””
2
0x12345678=0x12000000 + 0x340000 + 0x5600 + 0x78
(
)
12 34 56 78
0x12345678(0x12000000 + 0x340000 + 0x5600 +
printf("bit_order->a : %u\n", ptr->a); printf("bit_order->b : %u\n", ptr->b); printf("bit_order->c : %u\n", ptr->c);

c语言中整型数据的存储形式

c语言中整型数据的存储形式

c语言中整型数据的存储形式在C语言中,整型数据(Integer)在内存中的存储形式是固定长度的二进制数。

它们可以是带符号数或无符号数,以及不同的长度和大小。

先说一下带符号数。

带符号整型数据可以表示负值。

在C语言中,最常用的带符号整型数据类型是int(整型),它占用4个字节(32位),可以表示从-2147483648到2147483647的整数值。

在存储带符号整型数据时,使用的是“二进制补码”(Two's Complement)表示法。

这种表示法是如此普遍的原因是它符合自然的加减运算法则,同时可以在CPU中用简单的电路实现。

比如,如果要存储-5这个数,首先将它的绝对值转化成二进制:5的二进制是101,接着将所有位取反得到010,最后加1得到011,这就是-5以二进制补码形式的存储形式:11111111 1111 1011。

再说说无符号整型数据(Unsigned Integer)。

它只能表示正整数,但在同样大小的空间内可以存储更大的值。

在C语言中,最常用的无符号整型数据类型是unsigned(无符号整数),它占用4个字节(32位),可以表示从0到4294967295的正整数值。

在存储无符号整型数据时,直接使用二进制表示这个数即可。

比如,如果要存储123这个数,直接将它转化成二进制即可:0111 1011。

除了int和unsigned,还有short(短整型)和long(长整型)等整型数据类型。

它们分别占用2个字节和8个字节。

这些数据类型在不同的编译器中占用的字节数可能不同。

无论用哪种整型数据类型,在内存中存储一个整型数据需要使用一块固定长度的内存空间。

对于32位的int,就需要4个字节的内存空间。

每个字节(Byte)由8个比特(Bit)组成,因此int变量会占用32个比特的空间。

这32个比特的位序(Bit Order)在不同的编译器和计算机体系结构中可能不同。

在存储整型数据时,常常需要考虑大小端(Endianness)的问题。

字节序

字节序
1. Little endian:将低序字节存储在起始地址 2. Big endian:将高序字节存储在起始地址 LE little-endian 最符合人的思维的字节序,地址低位存储值的低位,地址高位存储值的高位 怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说低位值小,就应该放在内存地址小的地方, 也即内存地址低位 反之,高位值就应该放在内存地址大的地方,也即内存地址高位 BE big-endian 最直观的字节序,地址低位存储值的高位,地址高位存储值的低位 为什么说直观,不要考虑对应关系,只需要把内存地址从左到右按照由低到高的顺序写出把值按照通常的高 位到低位的顺序写出 两者对照,一个字节一个字节的填充进去
网络序
网络序
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保 证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
为了进行转换 bsd socket提供了转换的函数有下面四个 htons把unsigned short类型从主机序转换到网络序 htonl把unsigned long类型从主机序转换到网络序 ntohs把unsigned short类型从网络序转换到主机序 ntohl把unsigned long类型从网络序转换到主机序 在使用little endian的系统中这些函数会把字节序进行转换 在使用big endian类型的系统中这些函数会定义成空宏 同样在网络程序开发时或是跨平台开发时也应该注意保证只用一种字节序不然两方的解释不一样就会产生 bug.
谢谢观看ห้องสมุดไป่ตู้
字节序
字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前 还是后到的在前
01 常见序

字节序与位序

字节序与位序

补充知识:数据存储的字节序与位序1.2数据存储的字节序与位序在各种计算机体系结构中,对于字节、字等的存储机制有所不同。

对于同一个数值,在不同的计算机体系中会以相反的顺序记录。

例如,十六进制数值12345678H,在一种计算机架构下存储为12345678H,而在另一种计算机架构下会被存储为78563412H。

这就是按照不同的字节序进行存储的。

所以所谓的字节序指的就是长度跨越多个字节的数据的存放形式。

1.2.1 Endian的含义目前的存储器,多以字节为访问的最小单元,当一个逻辑上的单元必须分割为物理上的若干单元时就存在了先放谁后放谁的问题。

于是Endian的问题应运而生了。

对于不同的存储方法,就有Big-endien和Little-endian两个描述。

Big-endian和Little-endian这两个术语来自于Jonathan Swift的《格利佛游记》。

其中交战的两个派别无法就应该从哪一端—小端(Little-end)还是大端(Big-end)打开一个半熟的鸡蛋达成一致。

支持从小端打开鸡蛋的一派被称为Little-endian,支持从大端打开鸡蛋的一派则被称为Big-endian.在那个时代,Swift是在讽刺英国和法国之间的持续冲突。

后来,一位网络协议的早期开创者Danny .Cohen,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了。

1.2.2 Little-endian的含义Little-endian是一种小值的一端〔或序列中较不典型的值)存储在前的顺序,也就是说,最低字节存放在最低位,最高字节存放在最高位,反序排列。

依照人们的习惯来说,我们的文字及数字都是以从左到右的方式排列的,这似乎也被认为是自然的存储字符和数字方式。

然而,Little-endian却恰恰与我们的习惯相反。

例如,按照我们的习惯写一个十六进制数值56AB78EFH,把这个数值以Little-endian的方式表达出来,则是EF78AB56H。

字节顺序的定义

字节顺序的定义

字节顺序的定义
字节顺序(Byte Order)是指在计算机中,多字节数据如何以字节为单位进行存储和传输的格式。

计算机存储数据是以字节(Byte)为单位进行的,而多字节的数据(如整数、浮点数)需要按照一定的顺序将字节存储在内存中。

字节顺序有两种常见的表示方法:大端序(Big-endian)和小端序(Little-endian)。

在大端序中,最高有效字节(Most Significant Byte,MSB)存储在最低的内存地址处,而最低有效字节(Least Significant Byte,LSB)存储在最高的内存地址处。

即数据的高位字节存储在低位地址,低位字节存储在高位地址。

在小端序中,则恰恰相反,最低有效字节(LSB)存储在最低的内存地址处,而最高有效字节(MSB)存储在最高的内存地址处。

即数据的低位字节存储在低位地址,高位字节存储在高位地址。

在计算机领域中,大多数处理器和操作系统都采用了其中一种字节顺序作为默认的格式。

例如,x86架构的处理器多数采用
小端序,而网络协议常用的是大端序。

在进行数据传输和存储时,需要注意字节顺序的一致性,即发送和接收的系统要使用相同的字节顺序来解析数据。

如果不一致,可能会导致数据解析错误或传输错误。

为了保证数据的正确传输和解析,常用的方法是在传输时明确指定字节顺序,或者使用网络字节顺序(Network Byte Order)来规范数据传输的字节顺序。

网络字节顺序采用的是大端序。

在网络中,数据传输常采用网络字节顺序来确保跨平台的兼容性和数据的正确解析。

Endianness

字节序,又称端序,尾序,英文:Endianness。

在计算机科学领域中,字节序是指存放多字节数据的字节(byte)的顺序,典型的情况是整数在内存中的存放方式和网络传输的传输顺序。

Endianness有时候也可以用指位序(bit)。

大小端序跟硬件的体系结构有关,所有x86系列的pc机都是小端序,跟操作系统无关。

在x86系列的pc上的solaris系统是小端序,sun sparc平台的solaris是大端序。

MIP32是小端大端字节序,高字节存于内存低地址,低字节存于内存高地址;小端字节序反之。

如一个long型数据0x12345678大端字节序:内存低地址--> 0x120x340x56内存高地址--> 0x78小端字节序:内存低地址--> 0x780x560x34内存高地址--> 0x12但是,当传输的数据以一个字节一个字节的方式进行发送传输的话,就没有大段序、小端序的问题了联合(union)方式判断法在union中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。

即上述的union虽然定义了两个成员,但其实这个union只占用了4个字节(32位机器中),往a成员赋值,然后读取b就相读取a成员的低位第一个字节的值。

如果机器使用大端模式,则u.a=1那a的最高字节值为1;如果机器使用小段模式,则u.a=1则a的最低位字节为1。

上述可知b和a有相同的起始位,所以读取b如果等于1,则为小端模式,b为0则为大端模式程序:typedef union {int i;char c;}my_union;int checkSystem1(void){my_union u;u.i = 1;return (u.i == u.c);}---------------------作者:Z_hehe来源:CSDN原文:https:///z_hehe/article/details/53310157版权声明:本文为博主原创文章,转载请附上博文链接!Big-Endian: 低地址存放高位为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。

比特序字节序总结

⽐特序字节序总结内存地址概念内存字节地址(单位是字节,是最⼩可寻址地址单位)0 1 2 3 4 5 6 ... N- - - - - - - - -每个字节内部bit位也有地址编号(这个地址⽆法通过机器指令寻址)0 1 2 3 4 5 6 7- - - - - - - -⼀个4字节整数的地址结构如下字节0 字节1 字节2 字节301234567 01234567 01234567 01234567| |字节内第0bit,整数内第0bit 字节内第7bit,整数内第31bitCPU根据地址总线来寻址,⽐如⼀个4字节整数保存在内存0 1 2 3这4个字节中,给地址总线传⼊地址0就能读取这4个字节(32bit位)数字字节序概念⼀个多字节数据(处理器⽀持的原始数据⽐如整数短整数等等,结构体这种数据结构不算),内部字节排序不是唯⼀的,根据CPU不同分为两种litte-end和big-end对⼀个整数0x12345678在litte-end机器中的存储分配是78 56 34 12 (字节地址从低到⾼) 就是数据逻辑上的⾼字节存储在内存地址的⾼字节在big-end机器中的存储分配是12 34 56 78 (字节地址从低到⾼) 就是数据逻辑上的⾼字节存储在内存地址的低字节这个就是字节序概念⽐特序概念⼀个byte数据,内部的8位bit 也有排序,根据CPU不同分为2种litte-bit-endbig-bit-end⼀个字节数 0x83(⼆进制表⽰为10000011)在litte-bit-end机器中中存储分配(针对内存地址顺序)是11000001 (bit位地址从低到⾼) 就是数据逻辑上的⾼bit 存储在内存地址的⾼bit位在big-bit-end(针对内存地址顺序)10000011 (bit位地址从低到⾼) 数据逻辑上的⾼bit 存储在内地地址的低bit位这个就是bit序的概念,和字节序类似⽐特序影响⽬前计算机外设(包括⽹卡,硬盘等等)和CPU之间通过外部总线能⾃动正确的转换bit序,因为计算机外设交换都是字节流,⽽字节内部的bit 序⼜⾃动转换了,所以这个基本没有影响字节序影响涉及⼆进制多字节数据传输,存储等外部交换数据时,需要程序转换字节序,否则对⽅会因为字节序不⼀致导致解析错误⽐如⼀个整数直接发送给另外⼀个字节序不同的计算机,没有转换字节序,那对⽅就⽆法正确解析;同样的,⼀个整数写⼊磁盘,把这个⽂件拷贝给其他不同字节序的计算机系统,计算机读取后,虽然bit序正确,但是字节序不⼀致,导致解析错误编程注意点1.⽹络发送⼆进制数据,注意转换字节序2.⼆进制⽂件共享,注意约定双⽅的字节序3.C语⾔位域操作这个需要说明⼀下如下结构体struct tm{char t1:3,t2:2,t3:1;};⼀般C编译器会按位域定义顺序分配位域存储地址(字节内bit地址),从字节内低bit地址开始分配,分配如下0 1 2 3 4 5 6 7| | | | |------ ----- || | |t1 t2 t3在⼤端和⼩端机器上分配都是⼀样的,不过⼤端⼩端机器上⽣成的位域访问的汇编代码就不同了;在⼩端机器上访问t1,访问的是byte中的地址前3bit⽽在⼤端机器上访问t1,访问的也是byte中的地址前3bit这样的话,从⼩端传递过的数据到了⼤端后,bit序反转了,⼩端低bit地址(数据低位) 就到了⼤端⾼bit地址(数据低位),⽽⼤端机器访问t1时还是访问从低bit位开始的3个bit,导致访问不正确;这种情况,需要在定义结构体的时候,根据机器⼤⼩端,反序位域定义顺序,这样⼦就能正常访问了struct tm{#ifdef litte_endchar t1:3,t2:2,t3:1;#elsechar t3:1,t2:2,t1:3;#endif};。

网络字节序

6.2 字节序本节主要讲字节序(Byte Ordering)或者说数据存储优先顺序。

大端(big-endian),小端(little-endian)大端字节序与小端字节序(有的地方叫大端存储与小端存储)下面以整数1为例来说明16位整型数1的小端字节序第2个字节 第1个字节0000 0000 0000 0001MSB LSB十六进制表示:0x0001MSB:Most Significant Byte 最高有效字节LSB:Least Significant Byte 最低有效字节16位整型数1的大端字节序第2个字节 第1个字节0000 0001 0000 0000MSB LSB十六进制表示:0x0100十进制表示:25632位整型数1的小端字节序第4个字节 第3个字节 第2个字节 第1个字节0000 0000 0000 0000 0000 0000 0000 0001MSB LSB十六进制表示:0x0000000132位整型数1的大端字节序第1个字节 第2个字节 第3个字节 第4个字节0000 0001 0000 0000 0000 0000 0000 0000MSB LSB十六进制表示:0x01000000十进制表示:16777216主机字节序与网络字节序主机字节序,对于不同的处理器,可以采用不同的大小端字节序,我这里的主机字节序是采用小端字节序存储的。

网络字节序,TCP/IP协议栈规定用大端字节序。

对于TCP/IP应用程序,有下面四个用来在处理字节序和网络字节序之间实施转换的函数。

#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong); 返回值:以网络字节序表示的32位整数uint16_t htons(uint16_t hostshort);uint32_t ntohl(uint32_t netlong); 返回值:以主机字节序表示的32位整数uint16_t ntohs(uint16_t netshort);h --- host --- 主机字节序;n --- net --- 网络字节序;l --- long --- 长(4字节)整数s --- short --- 短(2字节)整数代码示例#include <stdio.h>#include <arpa/inet.h>void main(){uint32_t net_long = htonl(1);printf("net_long = %X\n", net_long); uint16_t net_short = htons(1);printf("net_short = %X\n", net_short); uint32_t host_long = ntohl(net_long); printf("host_long = %X\n", host_long); uint16_t host_short = ntohs(net_short); printf("host_short = %X\n", host_short); }执行结果如下:net_long = 1000000net_short = 100host_long = 1host_short = 1。

网络字节序

网络字节序是计算机通信中用于表示数字的一种标准格式。

它是一种将对象、变量或者数据的二进制数据组合法分组的顺序。

网络字节序由下面几个部分组成:网络字节顺序号(Network Byte Order),主机字节顺序号(Host Byte Order),Internet字节顺序(Internet Byte Order),Adobe字节顺序(Adobe Byte Order),IBM字节顺序(IBM Byte Order)。

网络字节序是大多数网络设备之间发送数据所需要使用的基本格式,特别是TCP/IP协议所使用的大多数都是采用网络字节序的。

它可以将数据传输中保持数值的一致,而且可以使得字节顺序可以在网络传输中的双向传输中正常被识别。

网络字节序最重要的作用之一就是防止不同系统带来的差异产生错误的结果,即错误的机器对网络字节序进行编解码可能导致数据损坏。

网络字节序为了解决网络/机器字节顺序之间的不一致,均衡了机器之间的不同,从而将数据在网络中传输的过程中保持一致。

此外,网络字节序还可以保证字节和字的正确转换,利用字节序,能够对所有主机都能完全正确的识别、处理、及传输,从而有助于网络设备和服务间正确传输数据。

综上所述,网络字节序主要用于消除网络设备和服务之间字节顺序之间的差异性,指定网络协议中所使用的数据格式,以及消除各种数据传输中可能出现的歧义,从而改善传输过程的效率。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

字节序(byte order)和位序(bit order)字节序(byte order)和位序(bit order)在网络编程中经常会提到网络字节序和主机序,也就是说当一个对象由多个字节组成的时候需要注意对象的多个字节在内存中的顺序。

以前我也基本只了解过字节序,但是有一天当我看到ip.h中对IP头部结构体struct iphdr的定义时,我发现其中竟然对一个字节中的8个比特位也区分了大小端,这时我就迷糊了,不是说大小端只有在多个字节之间才会有区分的吗,为什么这里的定义却对一个字节中的比特位也区分大小端呢?下面我们先看一下struct iphdr的定义,后文会解惑为什么要在一个字节中区分大小端。

struct iphdr {#if defined(__LITTLE_ENDIAN_BITFIELD)__u8 ihl:4,version:4;#elif defined (__BIG_ENDIAN_BITFIELD)__u8 version:4,ihl:4;#else#error "Please fix "#endif__u8 tos;__be16 tot_len;__be16 id;__be16 frag_off;__u8 ttl;__u8 protocol;__sum16 check;__be32 saddr;__be32 daddr;/*The options start here. */};字节序(Byte order)关于字节序的文章已经有很多了,在我这篇文章中不打算过多的说字节序,但是也不能完全脱离字节序因为后面的重点部分比特序跟字节序也有一定的相似度和联系。

字节序就是说一个对象的多个字节在内存中如何排序存放,比如我们要想往一个地址a中写入一个整形数据0x12345678,那么最后在内存中是如何存放这四个字节的呢?0x12这个字节值为最高有效字节,也就是整数值的最高位(在本文中0x12=0x12000000),0x78为最低有效字节。

图1:大端字节序上图是大端字节序的示意图,所谓”大端字节序”,便是指最高有效字节落在低地址上的字节存放方式。

图2:小端字节序而小端字节序就是最低有效字节落在低地址上的字节存放方式。

0x12345678=0x12000000 + 0x340000 + 0x5600 + 0x78,所以要想保持一个对象的值在大小端系统之间不变,那么就必须确保不同的系统能够正确的识别最高有效字节和最低有效字节(不能错误的识别最高、最低有效字节)。

同样的字节序12 34 56 78在大端序机器中会识别为0x12345678(0x12000000 + 0x340000 + 0x5600 +0x78=0x12345678),在小端序机器中识别为0x78563412(0x12 + 0x3400 + 0x5600 00+ 0x78000000=0x78563412)。

所以要想两者保持一致就必须确保系统能够正确的识别最高有效字节0x12和最低有效字节0x78,那么在小端系统中字节存放的顺序应该为78 56 34 12。

比特序(bit order)字节序是一个对象中的多个字节之间的顺序问题,比特序就是一个字节中的8个比特位(bit)之间的顺序问题。

一般情况下系统的比特序和字节序是保持一致的。

一个字节由8个bit组成,这8个bit也存在如何排序的情况,跟字节序类似的有最高有效比特位、最低有效比特位。

比特序1 0 0 1 0 0 1 0在大端系统中最高有效比特位为1、最低有效比特位为0,字节的值为0x92。

在小端系统中最高、最低有效比特位则相反为0、1,字节的值为0x49。

跟字节序类似,要想保持一个字节值不变那么就要使系统能正确的识别最高、最低有效比特位。

字节序转换函数ntohl(s)、htonl(s)在socket编程中经常要用到网络字节序转换函数ntohl、htonl 来进行主机序和网络序(大端序)的转换,在主机序为小端的系统中字节序列78 56 34 12(val=0x12345678)经过htonl转换后字节序列变成12 34 56 78:图3:htonl函数字节序转换后我在想是不是比特序也一同进行了转换?为什么会有这个疑问呢,因为前文可知系统的比特序和字节序是一致的,现在字节序已经从小端变成了大端那么比特序应该也要一起转换。

而且如果比特序不变化那么当这些字节到了目标大端序系统中后每一个字节的值都会发生变化,因为同样的比特序列在小端和大端系统中识别的字节值会不一样。

首先从htonl、ntohl的源码来看确实只进行了字节序的转换并没有进行比特序的转换,再有就是以前socket编程的时候只调用了ntohl、htonl等函数并没有调用(而且系统也没有提供)比特序转换函数,但是最后的结果都是正确的,并没有发现上面提到的字节值发生变化的问题。

那么这个”神奇”的事情是怎么解决的呢,好像系统本身就给我们”悄悄”的解决了我担心的问题。

答案我们下文揭晓。

比特(bit)的发送和接收顺序比特的发送、接收顺序是指一个字节中的bit在网络电缆中是如何发送、接收的。

在以太网(Ethernet)中,是从最低有效比特位到最高有效比特位的发送顺序,也就是最低有效比特位首先发送,参考资料:frame。

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

现在来回答一下第3节中的那个疑问:htonl、ntohl函数肯定是不会同步转换一个字节中的比特序的,因为如果比特序也发生了转换的话那么这个字节的值也就发生了变化,记住htonl、ntohl只是字节序转换函数。

比特序按照小端的方式发送,首先发送的是最低有效比特位,最后发送的是最高有效比特位,接收端的网卡在接收到比特序列后按照主机的比特序把接收到的”小端序”比特流转换成主机对应的比特序列。

可以假设存在ntohb、htonb(b代表bit)这样的两个函数,网卡进行了比特序的转换,不过是这两个函数是网卡自动调用的,我们平时不用关注。

按照规则,发送、接收的时候进行比特序的转换,那么就能保证在不同的机器之间进行通信不会发生我担心的字节值发生变化的问题。

结构体的位域关于C语言中结构体的位域可以参考这篇文章:/2013/05/21/talk-about-bitfield-in-c-again/,对于位域的具体用法、语法参考这篇文章即可有。

对于位域有一个约定:在C语言的结构体中如果包含了位域,如果位域A定义在位域B之前,那么位域A总是出现在低序的比特位。

在计算机中可寻址的最小单位为字节,bit是无法寻址的,但是为了抽象我们可以把计算机的最小寻址单位变成bit,也就是我们可以单独获得一个bit位。

我们有如下的一段代码:#includestruct bit_order{unsigned char a: 2,b: 3,c: 3;};int main(int argc, char *argv[]){unsigned char ch = 0x79;struct bit_order *ptr = (struct bit_order *)&ch;printf("bit_order->a : %u\n", ptr->a);printf("bit_order->b : %u\n", ptr->b);printf("bit_order->c : %u\n", ptr->c);return 0;}我们把代码在gentoo(intel小端机器)、hu-unix(大端机器)两个机器上面编译、运行,结果如下:liuxingen@ V6-Dev ~/station $ ./bitfiledbit_order->a : 1bit_order->b : 6bit_order->c : 3下面是hp-unix的运行结果# ./bitfiledbit_order->a : 1bit_order->b : 7bit_order->c : 1我们先分析一下gentoo上面的结果:图6:小端机器的位域示例从上图中我们很容易就能理解gentoo上面的输出结果,下面是hp-unix上面示意图:图7:大端机器的位域示例从上面的输出可以看到同样的代码在不同的机器中输出了不同的结果,也就是说我们的代码在不同的平台不能直接移植,导致这个问题的原因就是我们前面提到的关于位域的一个约定,定义在前面的位域总是出现在低地址的bit位中,因为不同的平台的比特序是不同的,但是我们定义的位域没有根据平台的大小端进行转换,最后就导致了问题。

那么如何解决这个问题,那就是在定义结构体中的位域时判断平台的大小端:#include#includestruct bit_order{#if defined(__LITTLE_ENDIAN_BITFIELD)unsigned char a: 2,b: 3,c: 3;#elif defined (__BIG_ENDIAN_BITFIELD)unsigned char c: 3,b: 3,a: 2;#else#error "Please fix "#endif};int main(int argc, char *argv[]){unsigned char ch = 0x79;struct bit_order *ptr = (struct bit_order *)&ch;printf("bit_order->a : %u\n", ptr->a);printf("bit_order->b : %u\n", ptr->b);printf("bit_order->c : %u\n", ptr->c);return 0;}到此我们也就解释了文章开头关于struct iphdr定义中的那个疑问。

最后给大家隆重介绍一篇文章,对我启发很大,文中的很多知识来自于它:byte order and bit order。

相关文档
最新文档