首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Base64编码C语言实现

Base64编码C语言实现

作者头像
yichen
发布2020-11-09 12:20:56
发布2020-11-09 12:20:56
1.7K00
代码可运行
举报
运行总次数:0
代码可运行

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于{\displaystyle \log _{2}64=6}{\displaystyle \log _{2}64=6},所以每6个比特为一个单元,对应某个可打印字符。3个字节相当于24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。它可用来作为电子邮件的传输编码

编码

一开始先要算一下一共多少位,比如对 qwer 进行编码

按照每 3 字节转为 4 个的规则,len(qwer) mod 3 = 1 也就是说多出来 1 字节,那我们要补充 2 字节进去才能凑够 3 字节

放在 C 语言里可以这么写,其中 src 是待编码的数据

代码语言:javascript
代码运行次数:0
运行
复制
char table[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//定义的字典,根据这个找具体在哪里
fill_bit=((3-strlen(src)%3)%3);
for(int k=0;k<fill_bit;k++){
    src[data_length+k]='0';
}
代码语言:javascript
代码运行次数:0
运行
复制

然后就到了编码部分了,在此之前还要先介绍一下位操作

每个字节有 8 bit,比如 q 就是 01110001,按位与操作 & 做的就是相同为 1 不同为 0

那 q 与 3 进行与运算就是(01110001 & 0011)= 1

左移、右移在下文中就理解为是把它直接移动就好了,比如 q 右移 2 位:就是 011100 01 的后两位给移动出去,只剩下前 6 位,然后前面补上两个 0

代码语言:javascript
代码运行次数:0
运行
复制
int j=0;
for(int i=0;i<data_length;i+=3){
    index=src[i]>>2;
    result[j++]=table[index];
    index=((src[i]&3)<<4)+(src[i+1]>>4);
    result[j++]=table[index];
    index=((src[i+1]&15)<<2)+(src[i+2]>>6);
    result[j++]=table[index];
    index=(src[i+2]&63);
    result[j++]=table[index];
    //<< >> 运算符的优先级低于+ -,注意加括号
}

index=src[i]>>2 是把第一个 'q' 向右移了 2 位,也就是取前 6 位,得到了 00011100 也就是 28

result[j++]=table[index] 然后在字典中找第几位,作为结果,在字典中第 28 个是 c,所以就有了编码后的第一个字符 'c'

src[i]&3 作用是取第一个 'q' 的后两位 01,然后 (src[i]&3)<<4 左移4位 010000,再加第二个 'w' src[i+1]>>4 右移 4 位得到的前 4 位 0111,加起来是 010111 也就是 23,在字典中第 23 位是 'X',得到编码后第二个字符

src[i+1]&15 是取第二个 'w' 后四位 0111(15 是 1111),左移 2 位得 00011100。第三个 'e' 右移 6 位 src[i+2]>>6 得到的前 2 位 01,加起来得到得到 00011101 = 29 在字典中第 29 位是 'd'

最后再直接取第三个 'e' 的后 6 位 src[i+2]&63(63 是 111111)

这样一个循环就结束了,把三个变成了四个

下一个循环中算上前面补充的两个 0 是这样分的:

011100 100000 000000 000000

然后把补充的字符替换为 '='

代码语言:javascript
代码运行次数:0
运行
复制
result_length=strlen(result);
for(int k=0;k<fill_bit;k++){
    result[result_length-1-k]=padding_char; 
}
代码语言:javascript
代码运行次数:0
运行
复制
cXdlcg==

解码

代码语言:javascript
代码运行次数:0
运行
复制
int findchr(char *array,char ch){
    for(int i=0;i<strlen(array);i++){
        if(array[i]==ch){
            return i;
        }
    }
    return 0;
}
代码语言:javascript
代码运行次数:0
运行
复制

对于前面编码的每一个字符,都要从 table 表里面去找对应的字符,比如 'A' 应该是 0

首先可以把前面的 = 换成 A,因为 A 在我们定义的字典中是 000000,跟前面补上的 0 是一样的

代码语言:javascript
代码运行次数:0
运行
复制
for(int i=0;i<base_len;i++){
    if(src[i]==padding_char)
        src[i]='A';
}
for(int i=0;i<base_len;i+=4){
    result[j++]=(findchr(table,src[i])<<2)+((findchr(table,src[i+1])& 0xF0)>>4);
    result[j++]=((findchr(table,src[i+1])& 0x0F)<<4)+((findchr(table,src[i+2])& 0x3C)>>2);
    result[j++]=((findchr(table,src[i+2])& 0x03)<<6)+(findchr(table,src[i+3]));
}
代码语言:javascript
代码运行次数:0
运行
复制

感觉里面这些与操作没啥用啊,不管与不与,都是那几位了

然后按照从表里面找出来的位置进行位操作,这里拿前面编码后的 cXdlcg== 来举例子

比如 'c' 在表中是第 28 位(00011100)向左移动 2 位,那他就是 01110000,再加上表中 'X' 是 23(00010111),向右移动 4 位得到 00000001,两者相加得到 01110001 即 113 也就是 'q'

剩下的也一样:

代码语言:javascript
代码运行次数:0
运行
复制
01110000 + 00000111 = 01110111 = 119 = 'w'
01000000 + 00100101 = 01100101 = 101 = 'e'

到这里,一轮就结束了,用了 src[0]、src[1]、src[2]、src[3],解码出来 qwe

接下来 src[4] 到了 'c',00100011

代码语言:javascript
代码运行次数:0
运行
复制
01110000 + 00000010 = 01110010 = 114 = 'r'
00000000 + 00000000 = 00000000 = null
00000000 + 00000000 = 00000000 = null

解码结束

C 语言文件:

https://pan.baidu.com/s/1mBQA9dT48Y1ZgnBUOui5lg

提取码: g79b

ps.源码是很久之前保存的,忘了是在哪里找的了,又搜了一下估计是来自这里:

https://eqqie.cn/index.php/laji_note/785/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陈冠男的游戏人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 编码
  • 解码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档