字符数组中存储顺序,可以理解为是内存中存储的顺序!!!!!
1、示例
uint16_t value = 0xabcd;
uchar ch[2];
memcpy(ch,&value,sizeof(uint16_t);
- 大端,即高位在起始地址位置:(可以理解为高个的为排头)
ch[0] = 0xab
ch[1] = 0xcd;
- 小端:即低位在起始地址位置。(可以理解为矮个的为排头)
ch[0] = 0xcd;
ch[1] = 0xab;
小结:memcpy是从低字节开始拷贝,没有问题,问题是cpu硬件的不同。
2、分析
htons:是主机字节序转成网络字节序;
ntohs:是网络字节序转成主机字节序;
由本文知,二者是同一个宏,可以通用,本质都是将字节序颠倒。
网络字节序是大端法排序
主机字节序,则会根据CPU、操作系统的不同而不同,可能是大端排序,也可能是小端排序
倘若,通信的两端环境完全相同,通信过程中,发送端和接收端都可以不必进行字节序转换;
但是,如果通信两端环境不同,则必须要先统一字节序,即通过htons或ntohs转为大端序。
即:
socket send端,将该主机的uint16_t,uint32_t类型数据分别使用htons,htonl转成大端排序,发送到报文中,(如果主机实际是大端,调用函数,实际上没操作,如果是小端,就给转成大端);
uint16_t send_value = 0xabcd;
htons(send_value);
保证如上例中,使报文数据流是先存 0xab,后存0xcd
socket recv端,收到的uint16_t,uint32_t类型的数据分别使用 ntohs,ntohl转成该主机对应的字节序形式(如果主机是大端,调用函数也不会转换,结果为0xabcd,如果主机是小端,使用该函数会将数据颠倒字节顺序(将0xab和0xcd的顺序调换,从而保证跟send端的数据保持一致)。
uchar ch[2]={0xab,0xcd};
uint16_t recv_value = *(uint16_t*)ch;
如果主机是大端序,则recv_value值为0xabcd; //与发送端的0xabcd匹配
如果主机是小端序,则recv_value值为0xcdab; //与发送端的0xabcd,不匹配
故需要使用ntohs函数,颠倒字节顺序
//报文数据
uchar ch[2]={0xab,0xcd};
uint16_t recv_value = *(uint16_t*)ch; //值为 0xabcd 或者 0xcdab
recv_value = ntohs(recv_value); //值为 0xabcd
除了使用:uint16_t recv_value = *(uint16_t*)ch; 方式外,
可以使用mecpy(&recv_value,ch,sizeof(uint16_t));
小结:
1)使用htons能够保证报文中的数据字节顺序跟实际书写的数据字节顺序完全一致。如上,要传的数据是0xabcd,使用htons后,报文中的一定是0xab,0xcd.
2)使用ntohs能够保证 收到的数据跟 报文中的数据字节顺序完全一致。如上,报文中数据顺序是0xab,0xcd,使用ntohs后,
收到的一定是0xabcd.
故为了方便移植,
send端:对于uint16_t 数据使用 htons , 对于uint32_t数据使用htonl;
recv端:对于uint16_t数据使用ntohs,对于uint32_t数据使用ntohl。
运用如上这两部就能保证,发送端与接收端的数据一致。
ps:在编程中,我们有时候会利用htons的特性,使数据存储的数组中两个字节与书写顺序相同。示例如下:
uchar ch[2];
uint16_t value = 0xAA01;
memcpy(ch,&value,sizeof(value));
printf("ch[0]=%02x,ch[1]=%02x\n",ch[0],ch[1]);
uint16_t value_1 = htons(value);
memcpy(ch,&value_1,sizeof(value_1));
printf("ch[0]=%02x,ch[1]=%02x\n",ch[0],ch[1]);
printf("value_1=%04x",value_1);
需要注意的是:value_1,在经过htons(value)后,值发生了变化!!!!
3、总结:
htons,ntohs二者是同一个宏,二者完全通用,其实质是如果主机序是小端,则字节序颠倒,如果是大端,则不变。
4、注意事项
因为int型数据,一个数据占多个字节,所以会产生字节序的问题,故需要调用htons,ntohs进行统一。
当数据时字符串数组,此时,报文数据就是一个字节,一个字节的存放,不存在字节的问题,也不需要调用htons,ntohs进行转换。