详解C语言的htons和htonl函数、大尾端、小尾端

在Linux和Windows网络编程时需要用到htons和htonl函数,用来将主机字节顺序转换为网络字节顺序。

     在Intel机器下,执行以下程序

 

int main()
{
   printf("%d /n",htons(16));
      return 0;
}

得到的结果是4096,初一看感觉很怪。

    解释如下,数字16的16进制表示为0x0010,数字4096的16进制表示为0x1000。 由于Intel机器是小尾端,存储数字16时实际顺序为1000,存储4096时实际顺序为0010。因此在发送网络包时为了报文中数据为0010,需要经过htons进行字节转换。如果用IBM等大尾端机器,则没有这种字节顺序转换,但为了程序的可移植性,也最好用这个函数。

   另外用注意,数字所占位数小于或等于一个字节(8 bits)时,不要用htons转换。这是因为对于主机来说,大小尾端的最小单位为字节(byte)。

什么是大端模式(big-endian),为什么使用大端模式(big-endian)。

uint16_t htons(uint16_t hostshort);
  htons的功能:将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian)
  参数u_short hostshort: 16位无符号整数
  返回值:TCP / IP网络字节顺序
  htons 是把你机器上的整数转换成“网络字节序”, 网络字节序是 big-endian,也就是整数的高位字节存放在内存的低地址处。 而我们常用的 x86 CPU (intel, AMD) 电脑是 little-endian,也就是整数的低位字节放在内存的低字节处。举个例子吧。假定你的port是0x1234,在网络字节序里 这个port放到内存中就应该显示成addr addr+1,也就是:0x12 0x34;而在x86电脑上,0x1234放到内存中实际是:addr addr+1,也就是:0x34 0x12。htons 的用处就是把实际内存中的整数存放方式调整成“网络字节序”的方式。

第一个问题:为什么使用两个字节,也就是16位来存储。

  这个简单一些,因为一个字节只能存储8位2进制数,而计算机的端口数量是65536个,也就是2^16,两个字节。

第二个为题:为什么计算机需要大端模式和小端模式?

  小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
  大端模式 :符号位的判定固定为第一个字节,容易判断正负。

    big endian:大尾端,也称大端(高位)优先存储。
    little endian:小尾端,也称小端(低位)优先存储。
 
   如下00000000 00000000 00000000 00000001的存储
       
    大尾端:  00000000 00000000 00000000 00000001
           addr+0    addr+1     addr+2   addr+3     //先存高有效位(在低地址)
  
   小尾端:  00000001 00000000 00000000 00000000
           addr+0    addr+1     addr+2   addr+3     //先存低有效位(在低地址)

 

 

 

   故要判断机器的体系结构是大尾端还是小尾端,以下程序可以完成任务:
  
   

#include <stdio.h>
int main()
{
    int tt = 1;
    char *c = (char*)(&tt);
    if(*c == 1)
    {
        printf("litte endian\n");
    }
    else
    {
        printf("big endian\n");
    }
    return 0;
}

 

大小尾端数据间的相互转换

/*
      usage: to convert between the form of big-endian and little-endian
      author: ydzhang
      date: 2008年12月6日20:23:48
*/
#include <stdio.h>
typedef unsigned int u32;
typedef unsigned short u16;

#define BSWAP_16(x) \
        (u16) ( ((((u16)(x) & 0x00ff)) << 8) \
        | (((u16)(x) & 0xff00) >> 8) )

u16 bswap_16(u16 x)
{
    return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}

u32 bswap_32(u32 x)
{
    return ((x & 0x000000ff) << 24) |
           ((x & 0x0000ff00) << 8) |
           ((x & 0x00ff0000) >> 8) |
           ((x & 0xff000000) >> 24);
}

int main()
{
     u16 num_16 = 0x1234;
     u32 num_32 = 0x12345678;

    printf("%x\n", bswap_16(num_16));
    printf("%x\n", BSWAP_16(num_16));
    printf("%x\n", bswap_32(num_32));
    return 0;
}
 

 

转载于:https://www.cnblogs.com/sddai/p/5790479.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值