【C++】循环数组实战:base16编码分析

Base16 编码

Base16,也称为 Hex(十六进制)编码,是一种将二进制数据转换为可打印字符的编码方式。它使用 16 个字符(0-9 和 A-F)来表示数据,每个字符对应 4 位二进制(半字节,nibble)。

编码过程:

将二进制数据按 4 位(半字节)分组。
每个半字节映射到一个十六进制字符。

十六进制字符:0123456789ABCDEF

编码示例

将字符串 "AB" 转换为 Base16:

字符串 "AB" 的 ASCII 值为:
'A' = 65(十进制) = 01000001(二进制)
'B' = 66(十进制) = 01000010(二进制)
每个字节分为两个半字节:
0100 0001 → 0100(4)和 0001(1) → 4 和 1 → 十六进制为 41
0100 0010 → 0100(4)和 0010(2) → 4 和 2 → 十六进制为 42
最终编码结果:4142

解码过程:

将每两个十六进制字符转换回 8 位(1 字节)二进制数据。
组合所有字节,恢复原始二进制数据。

解码示例

将 Base16 编码 "4142" 解码为原始数据:

将每两个字符分组:
41 → 十进制 65 → ASCII 字符 'A'
42 → 十进制 66 → ASCII 字符 'B'
最终解码结果:"AB"

基础知识

二进制的高位和低位

高位(MSB):
二进制数中,最左边的位(最高权重位)。
对数值大小的影响最大。例如,在8位二进制数 00000000变为10000000,这个数的值从0变为128。
低位(LSB):
二进制数中,最右边的位(最低权重位)。
对数值大小的影响最小。例如,在8位二进制数 00000000变为00000001,这个数的值从0变为 1。

与或非&|!

复习一下与或非

与 & 都1才1
0 & 1 = 0 ; 0 & 0 = 0 ; 1 & 1 = 1 ;

或 | 有1则1
0 | 0 = 0 ; 0 | 1 = 1 ;1 | 1 = 1 ;

非 !
!0 = 1 ; ! 1 = 0 ;

二进制 & 二进制 则是每位分别对应进行&操作
1010 & 0110
= 1&0 0&1 1&1 0&0
=0010

代码部分

工具>选项>设置一个字体,防止0Oo不好区分

准备工作:命名空间和头文件

定义一个编码表,类型为静态 常量

静态常量字符串 base16_enc_tab,用于将字节的高4位和低4位映射到Base16字符。

声明了一个字符串 base16str,用于存储Base16编码后的结果。

转化的代码如下

for (unsigned char c : teststr)使用范围for循环遍历 teststr 中的每个字节

unsigned char 是 C++ 中的一种基本数据类型,用于表示无符号的 8 位整数。它的取值范围是从 0 到 255,这使其非常适合用于表示单个字节的数据,特别是在处理二进制数据或字符编码时。
尽管 char 通常用于表示字符,但在某些情况下,unsigned char 更适合,特别是当你需要确保字符值不被解释为负数时。例如,在处理 UTF-8 编码的字符时,字节值可能大于 127,使用 unsigned char 可以避免符号扩展问题。
比如:一个字符”你“占三个字节,每个字节对应8位二进制:11100100 10111101 10100000将这些二进制转换为十进制就是228 189 160
char的范围是-128 到 127,unsigned char范围是 0 到 255,明显后者合适

for (unsigned char c : teststr)
{
}

h 是通过将字节 c 的二进制右移4位得到的,这相当于提取了字节的高4位。
例如字节为0100 0001,二进制右移4位为:0000 0100,成功得到高4位


char h = c >> 4;

l 是通过将字节 c 的二进制 二进制00001111(0b表示二进制) 进行&操作得到的,这相当于提取了字节的低4位。
因为不管谁&0000都是0000,不管谁&1111都是它本身
例如字节为0100 0001,& 二进制000011110000 0001 成功得到低4位


char l = c & 0b00001111;

base16_enc_tab 是一个包含Base16字符的字符串,用于将高4位和低4位映射到对应的十六进制字符。
这两行代码将高4位和低4位分别转换为Base16字符,并将它们追加到 base16str 中。

base16str += base16_enc_tab[h];
base16str += base16_enc_tab[l];

输出转换的Base16字符的字符串

cout << "Base16:\t" << base16str << endl;

解码的代码如下

定义字符串用于存放解码后的数据


string ostr; //解码的数据

定义一个编码表,类型为静态 常量

静态常量字符串 base16_dec_tab,用于将 ASCII 码映射到十六进制字符的数值表示。
ASCII '0'-'9' 的值是 48-57,'A'-'F' 的值是 65-70。


 const vector<char> base16_dec_tab{
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //0~9
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //10~19
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //20~29
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //30~39
     -1,-1,-1,-1,-1,-1,-1,-1,       //40~47
     0,1,2,3,4,5,6,7,8,9,           //48~57
     -1,-1,-1,-1,-1,-1,-1,          //58~64
     10,11,12,13,14,15              //65~70
 };

for 循环用于遍历字符串 base16str,每次迭代增加 2 个索引。这种模式通常用于处理十六进制字符串,其中每两个字符表示一个字节(8 位)的数据。


for (int i = 0; i < base16str.size();i += 2)
{
}

char ch = base16str[i];:从字符串 base16str 中提取第 i 个字符,并将其存储在字符变量 ch 中。
char cl = base16str[i + 1];:从字符串 base16str 中提取第 i + 1 个字符,并将其存储在字符变量 cl 中。
这样提取到了两个base16字符为一对
例如一个十六进制字符串 E4BDA0提取后变为"E4", "BD", "A0"


char ch = base16str[i];
char cl = base16str[i + 1];

unsigned char h = base16_dec_tab[ch];unsigned char l = base16_dec_tab[cl];
使用了查找表(lookup table)的方式将十六进制字符转换为对应的数值。
例如"E4", "BD", "A0"
'E'的ASCII 值为69对应数字为14(十进制),'4' 的ASCII 值为4转换为 4(十进制)。
'B' 的ASCII值是66对应11,'D'的ASCII值是66对应13
'A' 的ASCII值是65对应10,'0' 的ASCII值是48对应0


unsigned char h = base16_dec_tab[ch];
unsigned char l = base16_dec_tab[cl];

将h的二进制位数左移

14 的二进制是 1110 =》 1110 0000
11 的二进制是 1011 =》 1011 0000
10 的二进制是 1010 =》 1010 0000

将h的二进制|l的二进制

4 的二进制是 0100
13 的二进制是 1101
0 的二进制是 0000

1110 0000 | 0100 = 1110 0000 | 0000 0100 = 1110 0100
1011 0000 | 1101 = 1011 0000 | 0000 1101 = 1011 1101
1010 0000 | 0000 = 1010 0000 | 0000 0000 = 1010 0000


ostr += (h << 4 | l);

将二进制输出为字符串


cout << "解码后为:" << ostr << endl;

posted @ 2025-04-11 11:34  plusu  阅读(265)  评论(0)    收藏  举报