今天的在閱讀項目代碼的時候遇到的問題。
在研究之後,終於確定每次看到這樣的轉換問題都會搞不懂,每次都需要花時間繞來繞去的原因。
我在之前沒能弄清轉換的過程中,字符的計算機存儲方式和字符的輸出方式的區別,總是出現很多想當然的想法,所以總是在想問題的過程中沒頭沒腦的。
先說轉換的要求:
將字節流轉換成十六進制字符串。字節流,就是一個一個的字符組成的流,每個字符佔一個字節。十六進制字符串,也是由一個個字符組成的。
舉例將字節流“AB”轉換成十六進制字符串,最後得到的結果應該是“4142”
這是因爲字符‘A’就是十六進制的41即0x41,字符‘B’就是十六進制的42,即0x42。
下面來看一些知識。
一個字節在內存中的表現形式:
從0000 0000到1111 1111
按十進制輸出:
從0到255
按16進制輸出:
從0x00到0xFF
如果‘A'以二進制輸出則得到0100 0001
以十進制輸出則得到65
以十六進制輸出得到41
如果‘B'以二進制輸出則得到0100 0010
以十進制輸出則得到66
以十六進制輸出得到42
我們可以利用二進制和十六進制的轉換關係進行運算:
我們將一個字符的二進制表示劃分爲兩部分,其中前面半部分就是十六進制數的第二位,後半部分就是十六進制數的第一位。
<span style="white-space:pre"> </span>unsigned char c = 'A';
unsigned char pre = c >> 4;
unsigned char suf = c & 0x0F;
我們通過位移運算就可以得到‘A’的二進制表示的前半部分,通過與運算就可以得到‘A’的二進制表示的後半部分。
我們得到這些之後並不意味着轉換的結束,因爲我們得到的緊緊是十六進制表示爲4的字符,和十六進制表示爲1的字符,字符本身並不是我們想要的數值。如果我們將這些字符按照ascii字符輸出,他們並不是我們想要的結果,我們想要的結果是他們的字符表示是0~9和A~F。
下面我們就還需要進行轉換:
在上面的代碼中字符變量變量pre的十六進制表示是0x04,而實際的字符‘4’的十六進制表示是0x34,他們之間相差0x30.(在asc中所有的十六進制數與它所對應的ascii字符都相差0x30,所以只需要在原來的字符變量上加上0x30即可,0~9是這樣)
下面再看看例外:如果pre的十六進制表示是0x0A,此時是怎樣的呢?在ascii嗎表中,字符‘a’的十六進制表示是0x41,則需要在原來的字符變量上加上0x37.(A~E)
需要注意的內容大概就在上面這些了,下面看完整代碼(如有需要自行改動):
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
int main()
{
unsigned char c = 'A';
cout << "轉換前" << endl;
unsigned char pre = c >> 4;
printf("以十六進制輸出:0x%02x\n",pre);
printf("以ascii輸出:%c\n",pre);
unsigned char suf = c & 0x0F;
printf("以十六進制輸出:0x%02x\n",suf);
printf("以ascii輸出:%c\n",suf);
pre += 0x30;
if(pre >0x39)
{
pre += 0x07;
}
suf += 0x30;
if(suf >0x39)
{
suf += 0x07;
}
cout << "轉換後" << endl;
printf("以十六進制輸出:0x%02x\n",pre);
printf("以ascii輸出:%c\n",pre);
printf("以十六進制輸出:0x%02x\n",suf);
printf("以ascii輸出:%c\n",suf);
string s;
s += pre;
s += suf;
cout << "轉化後的十六進制字符串" << s;
return 0;
}