zoukankan      html  css  js  c++  java
  • 关于 htonl 和 ntohl 的实现

    因为需要直接处理一个网络字节序的 32 位 int,所以,考虑用自己写的还是系统函数效率更高。然后又了下面的了解。

    首先是系统函数 htonl ,我在 kernel 源码 netinet/in.h 找到如下定义:

    # if __BYTE_ORDER == __BIG_ENDIAN
    /* The host byte order is the same as network byte order,
       so these functions are all just identity.  */
    # define ntohl(x)    (x)
    # define ntohs(x)    (x)
    # define htonl(x)    (x)
    # define htons(x)    (x)
    # else
    #  if __BYTE_ORDER == __LITTLE_ENDIAN
    #   define ntohl(x)    __bswap_32 (x)
    #   define ntohs(x)    __bswap_16 (x)
    #   define htonl(x)    __bswap_32 (x)
    #   define htons(x)    __bswap_16 (x)
    #  endif
    # endif
    #endif

    可以看到,如果系统是 BIG_ENDIAN 那么网络字节序和运算字节序是一致的,如果是 LITTLE_ENDIAN 那么需要进行 __bswap_32() 操作。__bswap_32() 在 gcc 中实现,位于bits/byteswap.h(不要直接引用此文件;使用 byteswap.h 中的 bswap32 代替):

    /* Swap bytes in 32 bit value.  */
    #define __bswap_constant_32(x) 
         ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >>  8) |         
          (((x) & 0x0000ff00u) <<  8) | (((x) & 0x000000ffu) << 24))

    如果 CPU 直接支持 bswap32 操作,那这里该用汇编来写? 以提高效率。

    网络上是一个个字节传的,而 int 是 32 位,所以,我又定义了这个 union:

    union
    {
        unsigned int ber32;
        char mem[4];
    } currentData;

    这样,就直接把各个 byte 给直接取出来了。

    所以,按这个思路,完整的过程就是:

    #if BYTE_ORDER == BIG_ENDIAN
            #warning "BIG_ENDIAN SYSTEM!"
            currentData.ber32 = sampleValue;
    #elif BYTE_ORDER == LITTLE_ENDIAN
            #warning "LITTLE_ENDIAN SYSTEM!"
            currentData.ber32 = bswap_32(sampleValue);
    #else
            #error "No BYTE_ORDER is defined!"
    #endif
            sendBuf[bufPos++] = currentData.mem[0];
            sendBuf[bufPos++] = currentData.mem[1];
            sendBuf[bufPos++] = currentData.mem[2];
            sendBuf[bufPos++] = currentData.mem[3];

    从网络字节序取出数值时候,赋值和 bswap 过程反一下就好。

    从网络字节序直接恢复出数值的另一个思路是,既然网络字节序是确定的,那么可以用移位累加的方法直接求出这个 int,如下:

    sampleValue = 0;

    sampleValue += (buff[posOfSamples + 0] << (8 * 3)) );
    sampleValue += (buff[posOfSamples + 1] << (8 * 2)) );
    sampleValue += (buff[posOfSamples + 2] << (8 * 1)) );
    sampleValue += (buff[posOfSamples + 3] << (8 * 0)) );

    虽然后面一个比 bswap 多几个 cpu 时间,但是,明显可读性要高一些。

  • 相关阅读:
    植物大战僵尸 辅助 总结
    C# 操作地址 从内存中读取写入数据(初级)
    c# math
    c# 获取屏幕图片
    从客户端(editorValue="<p>xxxx</p>")中检测到有潜在危险的 Request.Form 值。
    三种常见的SQL分页语句
    Windows Installer 服务无法启动!
    无法访问windows installer服务
    mssql2000数据库执行SQL语句来创建数据库以及数据表还有索引
    如何安装aspjpeg
  • 原文地址:https://www.cnblogs.com/pied/p/5371231.html
Copyright © 2011-2022 走看看