htonl,htons,ntohl,ntohs的详解

大小端模式

对于多字节的数值在系统中如何存储取决于各CPU的实现,而高字节部分是存在低地址还是高地址就有不一样的结果了,因此才有大小端两种模式的存在,而命名则是根据起始地址存放的是数值字节的低处还是高处,如果是低处就是小端,高处就是大端,可以用代码来看看系统是如何存储的,从而确定目前的环境是小端还是大端

#include <stdio.h>
#include <arpa/inet.h>   /*在Linux上*/

void main() {
     printf("%d\n", ntohl(1));
     int num = 0x12345678;

     int i;
     for (i = 0; i < 4; ++i) {
         printf("%d:0x%x\n", i, *((char *)&num + i));
     }
     printf("%x\n", num);

     num = htonl(num);
     for (i = 0; i < 4; ++i) {
        printf("%d:0x%x\n", i, *((char *)&num + i));
     }
     printf("%x\n", num);
}

网络字节序

由于不同的系统会有不同的模式,为了统一,规定在网络传输中使用大端模式,这就是网络字节序。现在看看下面这四个函数的作用

uint32_t htonl(uint32_t hostlong);//32位的主机字节序转换到网络字节序
uint16_t htons(uint16_t hostshort);//16位的主机字节序转换到网络字节序
uint32_t ntohl(uint32_t netlong);//32位的网络字节序转换到主机字节序
uint16_t ntohs(uint16_t netshort);//16位的网络字节序转换到主机字节序

拿htonl和ntohl来分析,htonl函数的内部实现原理是这样,先判断主机是什么模式存储,如果是大端模式,就跟网络字节序一致,直接返回参数即可,如果是小端模式,则把形参转换成大端模式存储在一个临时参数内,再把临时参数返回;而ntohl函数的实现原理也是一样的过程,但是要注意它的参数,参数是网络字节序,就是大端模式存储,而不管你传入实参的过程是如果存储的,因此当判断主机是大端模式的时候,会直接返回,因为该函数默认会认为形参是网络字节序,把它当大端模式来看,如果判断主机是小端模式,就会将实参做转换,转换的过程并不复杂,就是逆序存储各个字节的数据,所以结果就被转换。

说到这里,可以看出一个规律来,就是如果主机与网络字节序不一致(也就是小端模式),这四个函数的返回值与传递进去的实参值的字节排序肯定是逆序的,所以返回值绝对不等于实参值,例如htonl(1)的结果肯定不是1,而如果主机与网络字节序一致(也就是大端模式),则这四个函数根本就没有做转换操作,而是直接返回实参值,这样他们的返回结果就肯定与实参值相同,即htonl(1)的结果是1。

这样,我们就得到了一个非常简便的判断系统是什么模式的方法,就是直接利用这四个函数来判断,如

if (1 != htonl(1)) {
    //小端模式,作相应处理
} else {
    //大端模式,作相应处理
}

或者直接用一个判断if(1 != htonl(1)),只有主机字节序与网络字节序不一致时,才调用那些函数去转换,否则不需要处理,这样可以减少多余的函数调用。

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值