ASC與HEX之間的轉換


ASC與HEX之間的轉換

         有這么兩個函數:

函數

原型

功能

返回值

參數

備注

hex2asc

__int16 hex2asc(unsigned char *strhex,unsigned char *strasc,__int16 length);

字符串轉換函數,十六進制字符轉換成普通字符

成功則返回 0,否則返回非0

strhex:要轉換的字符

strasc:轉換后的字符

length:字符strasc的長度

長轉短

asc2hex

__int16 asc2hex(unsigned char *strasc,unsigned char *strhex,__int16 length);

字符串轉換函數,普通字符轉換成十六進制字符

成功則返回0,否則返回非0

strasc:要轉換的字符

strhex:轉換后的字符

length:字符strasc的長度

短轉長

 

         我們首先對這兩個函數進行的測試如下:

// hex2asc和asc2hex的測試程序
#include "dculd.h"
#include <iostream>
using namespace std;

#pragma comment(lib, "dculd.lib")

int main()
{
    unsigned char strhex[101] = "0123456789ABCDEF";
    //unsigned char strhex[101] = "0123456789ABCD8";
    unsigned char strasc[101] = {0};

    hex2asc(strhex, strasc, 8);

    cout << "strhex: " << strhex << endl;
    cout << strlen((const char*)strhex) << endl;
    cout << strasc << endl;
    cout << strlen((const char*)strasc) << endl;

    cout << endl << "strasc DEC: ";
    for (int i = 0; i < strlen((const char*)strasc); ++i)
    {
        cout << dec << (int)strasc[i] << ' ';
    }

    cout << endl << "strasc HEX: ";
    for (int i = 0; i < strlen((const char*)strasc); ++i)
    {
        cout << hex << "0x" << (int)strasc[i] << ' ';
    }
    cout << endl;


    cout << endl;
    unsigned char strhex_2[101] = {0};
    asc2hex(strasc, strhex_2, 8);
    cout << "strhex_2: " << strhex_2 << endl;

    return 0;
}

         hex2asc和asc2hex這兩個函數本質上都是字符串轉換函數。其中,hex2asc的被轉化參數strhex為字符串”0123456789ABCDEF”,該字符串表示的是十六進制的值,每個元素相當於4個bit的值,所以每兩位相當於一個byte。該字符串每個元素的取值范圍為0~9和A~F,總共16個值,即16進制的16個數字。

         轉換后的參數strasc為字符串” #Eg壂惋”,該字符串的長度為8,每個元素的ASCII值為:

十進制:1 35 69 103 137 171 205 239

十六進制:0x1 0x23 0x45 0x67 0x89 0xab 0xcd 0xef

         具體轉換的規則為strhex中的兩個元素的字符串所代表的十六進制數,轉換為一個byte的ASCII值,然后將其存儲到strasc中,所以strhex的長度為strasc長度的兩倍。

         相應地,asc2hex函數是將strasc字符串中每個元素實際的ASCII值以十六進制的形式轉換為字符串,即用strhex存儲。

         這里的轉換是用的十六進制,strhex中的字符串都是以十六進制的形式存在,因為每個元素的值為0~9和A~F,所以hex2asc函數中的轉換操作必須是16進制的處理。asc2hex中也必須是十六進制的處理,如果改用十進制、八進制等其他進制操作,轉換后的strhex中的字符必定與原來的strhex不同,並且元素個數也有可能不同。

         關於為什么使用十六進制,這是我們預先規定的。如果不涉及A~F的字符,完全可以用十進制進行操作。

         另一個問題是為什么要進行hex和asc之間的轉換?hex更便於程序員自身識別,而asc更便於計算機識別,所以為了使得程序員更好的識別機器指令,在書寫的時候才有strhex的形式進行書寫,而非直接的strasc形式。機器執行字節碼指令的時候必然需要strasc的形式,所以需要hex2asc函數進行相應的轉換。asc2hex函數的作用是將機器返回的字節碼數據更友好地呈現給程序員識別,所以需要將asc轉換為hex的形式。通知hex2asc和asc2hex的轉換,既有利於程序員的指令識別,也有利於機器的指令識別。

         另外,用字節存儲十六進制的字符標識,可以節省空間,一個字節可以存儲兩個十六進制字符,如果感興趣,可以閱讀《字節存儲數據》。

         一般情況下,一個指令字節是八位,必然對應於strhex中的2個元素,所以,strhex的長度一般情況下都是偶數的,對於基數的情況上述hex2asc函數會導致轉換錯誤:

對於最后一個單獨的元素’8’,hex2asc函數將其轉換為字節:0x50,十進制的80,兩個strhex元素對應於一個strasc元素,所以當strhex的長度為奇數時會存在這種情況。asc2hex函數不會存在這種問題,因為asc2hex是將strasc中的每個元素轉換為strhex中的兩個元素,不存在奇偶性的問題。

針對以上奇偶性的問題,我們隊hex2asc進行相應的改進,使其可以處理strhex長度為奇數的情況,當然針對字節指令一般情況下不會存在這種問題,因為如果strhex長度為奇數,hex2asc應該返回錯誤信息。對hex2asc改進的同時,需要對asc2hex進行改進,使其可以處理strhex長度為奇數的情況。

另外,hex2asc和asc2hex第三個參數length是標識了字節指令的字節個數,即strasc和strhex都可以支撐length,也就是說strasc的長度大於等於length,strhex的長度大於等於length*2。在我們的實現代碼中,length的意義有所改變,HexToAsc的length參數是指的轉換strhex的元素個數,所以length可以為奇數。AscToHex的length參數是指的轉換strasc的元素個數,length可以向原來的參數那樣可以是偶數也可以是奇數。但是length的值在HexToAsc中需要小於等於strhex的元素個數,在AscToHex中需要小於等於strasc的元素個數,在兩個函數中需要同時考慮處理strhex奇數長度的情況。

下面我們對hex2asc和asc2hex進行重新實現,具體代碼如下:

// hex2asc和asc2hex的重實現,可以處理strhex長度為奇數的情況
#include <iostream>
using namespace std;

// 將a~f轉換為A~F
unsigned char ToUpperHex(unsigned char& ch)
{
    if (ch >= 'a' && ch <= 'f')
    {
        ch = 'A' + ch - 'a';
    }
    return ch;
}

// 檢測ch是否為十六進制字符
bool IsHex(unsigned char ch)
{
    return ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f';
}

int HexVal(unsigned char ch)
{
    if (ch >= '0' && ch <= '9')
    {
        return ch - '0';
    }
    else if (ch >= 'A' && ch <= 'F')
    {
        return 10 + ch - 'A';
    }
    else if (ch >= 'a' && ch < 'f')
    {
        return 10 + ch - 'a';
    }
    else
    {
        return -1;
    }
}

unsigned char ValHex(int val)
{
    if (val >= 0 && val <= 9)
    {
        return val + '0';
    }
    else if (val >= 10 && val <= 15)
    {
        return val - 10 + 'A';
    }
    else
    {
        return '$';
    }
}

int HexToAsc(unsigned char* strhex, unsigned char* strasc, int length)
{
    //if (length % 2 == 1) // length表示轉換strhex的元素個數,如果嚴格要求只能轉換偶數個,這里可以進行判斷
    //{
    //    return -1;
    //}
    if (length > strlen((const char*)strhex))
    {
        length = strlen((const char*)strhex);
    }

    // 檢測strhex是否合法,是否存在非0~9、A~F、a~f字符
    for (auto i = 0; i != length; ++i)
    {
        if (!IsHex(strhex[i]))
        {
            return -2;
        }
    }

    // 以下for-if結構可以同時處理奇偶的情況
    int pos = 0, i = 0;
    for (i = 0; i < length - 1; i += 2)
    {
        unsigned char tmp = HexVal(strhex[i]) * 16 + HexVal(strhex[i + 1]);
        strasc[pos++] = tmp;
    }
    if (i == length - 1)
    {
        unsigned char tmp = HexVal(strhex[i]) * 16;
        strasc[pos++] = tmp;
        
        // 用來標識length的奇偶,這里是奇數
        strasc[pos++] = 1;
    }
    else
    {
        // 用來標識length的就,這里偶數
        strasc[pos++] = 2;
    }
    strasc[pos++] = 0;
    return 0;
}

int AscToHex(unsigned char* strasc, unsigned char* strhex, int length)
{
    length = length <= strlen((const char*)strasc) - 1 ? length : strlen((const char*)strasc) - 1;

    // strasc中的元素不存在合不合法的情況,所以不做檢測

    int i = 0, pos = 0;
    for (i = 0; i < length - 1; ++i) // 這里先處理length-1個字符,第length個字符后續處理,因為需要考慮奇偶的情況
    {
        strhex[pos++] = ValHex(strasc[i] / 16);
        strhex[pos++] = ValHex(strasc[i] % 16);
    }

    if (strasc[strlen((const char*)strasc) - 1] == 1) // 奇數的情況
    {
        strhex[pos++] = ValHex(strasc[length - 1] / 16);
    }
    else if (strasc[strlen((const char*)strasc) - 1] == 2) // 偶數的情況
    {
        strhex[pos++] = ValHex(strasc[length - 1] / 16);
        strhex[pos++] = ValHex(strasc[length - 1] % 16);
    }

    strhex[pos++] = 0;
    return 0;
}

int main()
{
    unsigned char strhex[101] = "0123456789ABCDEF";
    //unsigned char strhex[101] = "0123456789ABCD8";
    unsigned char strasc[101] = {0};

    HexToAsc(strhex, strasc, 16); // 這里的16標識的是轉換strhex的元素個數
    //HexToAsc(strhex, strasc, 15); // 這里的15標識的是轉換strhex的元素個數

    cout << "strhex: " << strhex << endl;
    cout << strlen((const char*)strhex) << endl;
    cout << strasc << endl;
    cout << strlen((const char*)strasc) << endl;

    cout << endl << "strasc DEC: ";
    for (int i = 0; i < strlen((const char*)strasc); ++i)
    {
        cout << dec << (int)strasc[i] << ' ';
    }

    cout << endl << "strasc HEX: ";
    for (int i = 0; i < strlen((const char*)strasc); ++i)
    {
        cout << hex << "0x" << (int)strasc[i] << ' ';
    }
    cout << endl;


    cout << endl;
    unsigned char strhex_2[101] = {0};
    AscToHex(strasc, strhex_2, 8); // 這里的8標識的是轉換strasc的元素個數
    cout << "strhex_2: " << strhex_2 << endl;

    return 0;
} 

         以上是針對length值為偶數的情況。如果length為奇數,我們有如下測試:

         從測試中,我們可以看出,即便是轉換奇數個strhex元素的情況,我們也可以照常進行處理。下面是我們對程序的說明:

         這是我們的函數原型,其中length參數在HexToAsc中我們指代的是轉換strhex的元素個數,既可以是偶數也可以是奇數。AscToHex中的length參數是標識轉換strasc的元素個數,可以是偶數也可以是奇數。

int HexToAsc(unsigned char* strhex, unsigned char* strasc, int length);

int AscToHex(unsigned char* strasc, unsigned char* strhex, int length);

         程序中我們定義了一下幾個函數:

         ToUpperHex,用來將a~f轉換為A~F,我們並沒有用到該函數。

         IsHex,用來檢測strhex的合法性。

         HexVal,用來得到十六進制字符的實際值。

         ValHex,用來根據實際值得到十六進制的字符,這里都是轉換為A~F字符,而非a~f。

         HexToAsc函數中,我們首先檢測length的長度,如果大於strhex的長度,則將其更改為strhex的長度,然后檢測strhex的合法性。根據for-if-else結構來處理length奇偶數的情況。我們在strasc最后一位設定了一個標識元素,用來標識length的奇偶性。該標識在AscToHex函數轉換中也要用到。

         AscToHex函數一開始也要檢測length的長度,由於strasc最后一個元素是標示了奇偶性,所以我們需要檢測length與strasc長度減一的關系。然后我們對0到length-2元素進行諸位轉換,針對length-1元素,我們需要判斷strasc最后一個元素的標識,根據其標識的奇偶性來進行轉換。

         通過我們重實現的HexToAsc和AscToHex,我們可以正常的處理轉換strhex元素個數為奇數的情況。

         需要注意的一點是,length參數標注的是要轉換的元素個數,如果大於原來的元素個數,則全部轉換,如果小於,則只轉換length個元素。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM