用C++实现ASCII码字符数组转16进制字符数组的功能

来源:互联网 发布:大巴车出租软件 编辑:程序博客网 时间:2024/05/30 04:29
    在网络通信中经常用到16进制字符数组和ASCII码字符数组互相转换的功能,虽然功能简单,但初学者写出来的代码经常会有各种问题。从ASCII码字符数组转为16进制字符数组,一个判断比较完整的实现代码如下:
bool AsciiToHex( char * Dest, char * Src, int SrcLen )
{
    if ( ( Dest == NULL ) || ( Src == NULL ) )
    {
    return false;
    }


    for ( int i = 0, j = 0; i < SrcLen; j++ )
    {
         unsigned char HiHalf = ( unsigned char ) Src[i++] ;
         unsigned char LoHalf = ( unsigned char ) Src[i++] ;


         if ( HiHalf >= 'a' && HiHalf <= 'z' )
         {
          HiHalf -= ( 'a' - 10 );
         }
         else if ( HiHalf >= 'A' && HiHalf <= 'Z' )
         {
          HiHalf -= ( 'A' - 10 );
         }
         else if ( HiHalf >= '0' && HiHalf <= '9' )
         {
          HiHalf -= '0';
         }
         else
         {
          return false; 
         }


         if ( LoHalf >= 'a' && LoHalf <= 'z' )
         {
          LoHalf -= ( 'a' - 10 );
         }
         else if ( LoHalf >= 'A' && LoHalf <= 'Z' )
         {
          LoHalf -= ( 'A' - 10 );
         }
         else if ( LoHalf >= '0' && LoHalf <= '9' )
         {
          LoHalf -= '0';
         }
         else
         {
          return false; 
         }


         Dest[j] = ( HiHalf << 4 ) | LoHalf;
    }


    return true;
}


    以上代码中,比较了Dest和Src是否为NULL,还判断了字符数组Src里是否有非法字符(即0-9、A-Z、a-z以外的字符),进行计算的时候也使用了更安全的unsigned char类型,看起来很不错。但当SrcLen参数错误,为奇数时Dest会多写一个字节,可能会导致数组越界。 另外以上代码在效率上有严重的问题。一般我们在通信中是把10-15转为大写的A-F,以上代码先和小写字母判断,会导致一些无用功。另外被转换的Src字符为0-15,数字0-9有10个,字母A-F有6个,理论上出现数字的概率大。所以要先判断是否数字,再判断是否大写字母,最后判断是否小写字母,剩下的就是非法字符了。比较代码就应该如下:
         if ( HiHalf >= '0' && HiHalf <= '9' )
         {
          HiHalf -= '0';
         }
         else if ( HiHalf >= 'A' && HiHalf <= 'F' )
         {
          HiHalf -= ( 'A' - 10 );
         }
         else if ( HiHalf >= 'a' && HiHalf <= 'f' )
         {
          HiHalf -= ( 'a' - 10 );
         }
         else
         {
          return false; 
         }
在修正后的比较代码中,仍然有效率问题。举例如下,当HiHalf等于'A'时,因为 '0' < '9' < 'A' < 'F' < 'a' < 'f',HiHalf分别和'0'、'9'、'A'、‘F’做了4次比较。如果我们将代码改为:
         if ( HiHalf <= '9' && HiHalf >= '0' )
         {
          HiHalf -= '0';
         }
         else if ( HiHalf <= 'F' && HiHalf >= 'A' )
         {
          HiHalf -= ( 'A' - 10 );
         }
         else if ( HiHalf <= 'f' && HiHalf >= 'a' )
         {
          HiHalf -= ( 'a' - 10 );
         }
         else
         {
          return false; 
         }
那么HiHalf和'9'比较后,就不会再和'0'去比较了,比较次数从4次变成了3次。同理对小写字母来说,比较次数减少了2次。
    另外为了调用方便,将Src、Dest的类型从char *改为void *。最终版本的代码如下:
 bool AsciiToHex( void * DestBuf, void * SrcBuf, int SrcLen )
{
    if ( ( DestBuf == NULL ) || ( SrcBuf == NULL ) )
    {
    return false;
    }


    unsigned char * Dest = ( unsigned char * ) DestBuf;
    unsigned char * Src = ( unsigned char * ) SrcBuf;
    int DestLen = SrcLen >> 1;


    for ( int SrcPos = -1, DestPos = 0; DestPos < DestLen; )
    {
         unsigned char HiHalf = Src[++SrcPos];
         unsigned char LoHalf = Src[++SrcPos];


         if ( HiHalf <= '9' && HiHalf >= '0' )
         {
          HiHalf -= '0';
         }
         else if ( HiHalf <= 'F' && HiHalf >= 'A' )
         {
          HiHalf -= 55;
         }
         else if ( HiHalf <= 'f' && HiHalf >= 'a' )
         {
          HiHalf -= 87;
         }
         else
         {
          return false; 
         }


         if ( LoHalf <= '9' && LoHalf >= '0' )
         {
          LoHalf -= '0';
         }
         else if ( LoHalf <= 'F' && LoHalf >= 'A' )
         {
          LoHalf -= 55;
         }
         else if ( LoHalf <= 'f' && LoHalf >= 'a' )
         {
          LoHalf -= 87;
         }
         else
         {
          return false; 
         }


         Dest[DestPos++] = ( HiHalf << 4 ) | LoHalf;
    }


    return true;
}


    有兴趣的同学可以写个单元测试验证一下转化结果。或者用效率更高的查表法来实现,节省更多计算步骤和时间。 

0 0