今天的在阅读项目代码的时候遇到的问题。
在研究之后,终于确定每次看到这样的转换问题都会搞不懂,每次都需要花时间绕来绕去的原因。
我在之前没能弄清转换的过程中,字符的计算机存储方式和字符的输出方式的区别,总是出现很多想当然的想法,所以总是在想问题的过程中没头没脑的。
先说转换的要求:
将字节流转换成十六进制字符串。字节流,就是一个一个的字符组成的流,每个字符占一个字节。十六进制字符串,也是由一个个字符组成的。
举例将字节流“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;
}