一、字节序
对一个主机系统来说,存储的空间总是有高位和低位的,那么对于一个数据来说,数据的高位和地位与存储空间的高位和低位如何对应,这就是字节序的问题。
字节序有两种:大端(big-endian)和小端(little-endian)。简单描述如下
大端:数据的高位对应存储空间的低位,数据的低位对应存储空间的高位
小端:数据的高位对应存储空间的高位,数据的低位对应存储空间的低位
举例:
一个2字节的数HByte,LByte。那么存储的情况如下
对于大端来说,存储结构如下
+--------+ 高位
| LByte |
+--------+
| HByte |
+--------+ 低位
假设有个数a=0x12345678,那么实际的存储顺序就是
|12|34|56|78|
低位 高位
也就是说,如果要在网络上发送的话,先发送的就是12
对于小端,刚好反过来,存储结构如下
+--------+ 高位
| HByte |
+--------+
| LByte |
+--------+ 低位
对于数0x12345678来说,存储顺序就是
|78|56|34|12|
低位 高位
如果要在网络上发送,就先发送78
二、网络序和主机序
就如同上面的例子中说的那样,同一个数据,对于大端和小端两种系统,向网络上发送数据的顺序是不同的,这样就可能出现问题。
比如一个大端的系统发送了0x12345678这个数据,那么发送的顺序是先发12,最后发送78。收到的时候也是先收到12,最后收到78。如果接收的系统也是大端的没有问题,但如果接收系统是小端的,那么该数据就可能被解析成0x78563412,因为小端系统认为先发送的字节应该是最低的字节。 这就出问题了。所以必须有一个规范,这就是主机序和网络序的概念。
网络序规定是大端序的。主机序则根据主机来决定。
按照规定,在网络上发送的数据都必须是网络序的,主机上的数据如果需要发送到网络上都应该先转成网络序。收到数据后,在转成本机的主机序。这样就不会出问题了。
主机序和网络序的转换有一些宏,比如:hton ntoh,htons ntohs,htonl ntohl
还是上面那个0x12345678为例
大端序的系统发送的时候,将消息转成网络序,发送,也就是12 34 56 78这个顺序
小端系统收到的时候,将网络序的消息,转成主机序,也就是将大端序的消息转成小端序。这样,在内存中本来应该是 +低位|12|34|56|78|高位+这样存放次序的消息,就转成了+低位|78|56|34|12|高位+,也就是在小端序下能正确解析成0x12345678了。
三、位序
也就是位域中的顺序问题
比如
struct bitfield
{
char a1:1;
char a2:1;
char a3:1;
char a4:1;
char a5:1;
char a6:1;
char a7:1;
char a8:1;
};
做如下赋值
struct bitfield testbit;
memset(&testbit;,0,sizeof(struct bitfield));
testbit.a8 = 1
那么输出的testbit的结果会是多少呢?
大端序系统中,输出结果为1,小端系统中输出结果为-128。为什么会是这个结果呢,分析如下
1.ANSI-C要求在struct里面,先声明的成员占有低地址。不管是大端还是小端系统都是这个要求。
根据这个要求,a8就是处于高位得。假设左边是高地址,责这个赋值后,testbit得值如下
1000 0000
2.小端系统(比如IA32)中,高位在高地址,低位在低地址,这样a8=1就是表示最高位为1,所以这个值就是-128了
3.大端系统中,高位在低地址,低位在高地址,也就是a8=1表示得是最低位,一个字节得最低位为1,其位为0,最后得值自然也就是1了。
四、位序结构占用得内存大小
如下结构定义
struct filedsize
{
short a1:3;
short a2:2;
short a3:3;
char byte1;
};
假设都是1字节对齐,那么sizeof(struct filedsize)会是多少呢?
不同得系统会有不同得值:
在windows系统中,这个值是3,
在vxworks系统中,这个值是2
这应该是在不同的系统下对内存的优化算法不同导致,还没有仔细研究过