1. 程式人生 > >用C++實現ASCII碼字元陣列轉16進位制字元陣列的功能

用C++實現ASCII碼字元陣列轉16進位制字元陣列的功能

    在網路通訊中經常用到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;
}


    有興趣的同學可以寫個單元測試驗證一下轉化結果。或者用效率更高的查表法來實現,節省更多計算步驟和時間。