网络字节序和本机字节序
1.字节序定义:是指整数在内存中保存的顺序。
2.字节序种类:
a.Little endinan 低位存储在内存的低地址,高位存储在内存的高地址;
b.Big endian 高位存储在内存的低地址,低位存储在内存的高地址;
3.例子:
DWORD dwCount = 0x01020304;这样的一个双字节变量在内存中如下分布0013FF70 04 03 02 01
(注:实验结果取之 XPSP3 VC6.0,说明我的机器是Little endinan序)
而如果是Big endian序的话,应该是0013FF70 01 02 03 04。用的比较多的x86系列的CPU,都是Little endinan序的。
而网络字节序这是TCP/IP协议中定义好的一种数据表示格式,它是与你的机器的cpu,操作系统什么的无关的,这样可以保证数据在网络中传输时,不管怎么样都能正确的解释了,网
络字节序选择了Big endian。这样就给编写网络程序的程序员带来一个问题,程序员必须把本地数据从主机字节序转换成网络字节序发送到主机,同时,主机也必须把收到的数据从网
络字节序转换成本地字节序,这样才能保证双方正确的收发数据,不然就是产生bug。
4.winapi提供了四个函数用于进行网络字节序到本机字节序和本机字节序到网络字节序的转换:
htons:把unsigned short类型从主机序转换到网络序
htonl:把unsigned long类型从主机序转换到网络序
ntohs:把unsigned short类型从网络序转换到主机序
ntohl:把unsigned long类型从网络序转换到主机序
(这四个API可以这样记,s表示short,l表示long,n表示network,h表示host)
另外:char类型是没有字节序的问题的,只有大于一个字节的数据类型才有字节序的问题。很多翻译书籍将Little endinan翻译成小端模式,将Big endian翻译成大端模式。
5.用代码判断是否是大小端:
a.
1 bool IsLittleEndinan1() 2 { 3 int i = 1; 4 char *p = (char *)&i; 5 return *p == 1; 6 }
大小端存储问题,如果小端方式中(i占至少两个字节的长度)则i所分配的内存最小地址那个字节中就存着1,其他字节是0。大端的话则1在i的最高地址字节处存放,char是一个字
节,所以强制将char型量p指向i则p指向的一定是i的最低地址,那么就可以判断p中的值是不是1来确定是不是小端。
b.
1 bool IsLittleEndinan2() 2 { 3 union u 4 { 5 int a; 6 char b; 7 }c; 8 c.a = 1; 9 10 return c.b == 1; 11 }
内存地址 | 0x4000 | 0x4001 |
存放内容 | 0x34 | 0x12 |
内存地址 | 0x4000 | 0x4001 |
存放内容 | 0x12 | 0x34 |
内存地址 | 0x4000 | 0x4001 | 0x4002 | 0x4003 |
存放内容 | 0x78 | 0x56 | 0x34 | 0x12 |
内存地址 | 0x4000 | 0x4001 | 0x4002 | 0x4003 |
存放内容 | 0x12 | 0x34 | 0x56 | 0x78 |
所谓的小端模式,是指数据的低位保存在内存的低地址中,而数 据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小 端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模 式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址单元
x1=((char*)&x)[1]; //高地址单元
若x0=0x11,则是大端; 若x0=0x22,则是小端......
上面的程序还可以看出,数据寻址时,用的是低位字节的地址。