
Base64是一种常见的编码方式,用于将二进制数据转换为可打印的ASCII字符,广泛应用于网络传输、数据存储等场景。本文将详细讲解一个用C语言实现的Base64编码解码程序。
我们的程序包含以下几个主要部分:
下面是完整的实现代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Base64编码表,包含64个可打印字符
constchar base64_encoding_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// Base64解码表,用于快速查找字符对应的数值
// 非Base64字符对应的值为-1
constint base64_decoding_table[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
// 计算Base64编码后的长度
size_t base64_encoded_length(size_t input_length) {
// 公式:(输入长度 + 2) / 3 * 4
// +2是为了确保除法向上取整
return (input_length + 2) / 3 * 4;
}
// 计算Base64解码后的长度
size_t base64_decoded_length(const char *input) {
size_t length = strlen(input);
size_t padding = 0;
// 检查填充的'='数量
if (length > 0 && input[length - 1] == '=') padding++;
if (length > 1 && input[length - 2] == '=') padding++;
// 公式:(输入长度 / 4) * 3 - 填充数
return (length / 4) * 3 - padding;
}
// Base64编码函数
// 参数:输入数据,输入长度
// 返回:编码后的字符串(需要调用者释放内存)
char *base64_encode(const unsigned char *input, size_t input_length) {
// 计算输出长度并分配内存
size_t output_length = base64_encoded_length(input_length);
char *output = (char *)malloc(output_length + 1); // +1 用于存储终止符'\0'
if (output == NULL) {
returnNULL; // 内存分配失败
}
size_t i, j;
// 每次处理3个输入字节,生成4个输出字符
for (i = 0, j = 0; i < input_length; i += 3, j += 4) {
// 读取3个输入字节,不足则用0填充
unsignedchar byte1 = input[i];
unsignedchar byte2 = (i + 1 < input_length) ? input[i + 1] : 0;
unsignedchar byte3 = (i + 2 < input_length) ? input[i + 2] : 0;
// 将3个8位字节合并为一个24位整数
unsignedint value = (byte1 << 16) | (byte2 << 8) | byte3;
// 从24位整数中提取4个6位值,并映射到编码表
output[j] = base64_encoding_table[(value >> 18) & 0x3F];
output[j + 1] = base64_encoding_table[(value >> 12) & 0x3F];
// 处理填充:如果原始数据不足3字节,用'='填充
if (i + 1 < input_length) {
output[j + 2] = base64_encoding_table[(value >> 6) & 0x3F];
} else {
output[j + 2] = '=';
}
if (i + 2 < input_length) {
output[j + 3] = base64_encoding_table[value & 0x3F];
} else {
output[j + 3] = '=';
}
}
output[output_length] = '\0'; // 添加字符串终止符
return output;
}
// Base64解码函数
// 参数:输入字符串,输出长度指针
// 返回:解码后的二进制数据(需要调用者释放内存)
unsigned char *base64_decode(const char *input, size_t *output_length) {
size_t input_length = strlen(input);
// 检查输入长度是否为4的倍数,这是Base64格式要求
if (input_length % 4 != 0) {
*output_length = 0;
returnNULL;
}
// 计算输出长度并分配内存
*output_length = base64_decoded_length(input);
unsignedchar *output = (unsignedchar *)malloc(*output_length);
if (output == NULL) {
*output_length = 0;
returnNULL;
}
size_t i, j;
// 每次处理4个输入字符,生成3个输出字节
for (i = 0, j = 0; i < input_length; i += 4, j += 3) {
// 从解码表中获取4个6位值
int val1 = base64_decoding_table[(unsignedchar)input[i]];
int val2 = base64_decoding_table[(unsignedchar)input[i + 1]];
int val3 = base64_decoding_table[(unsignedchar)input[i + 2]];
int val4 = base64_decoding_table[(unsignedchar)input[i + 3]];
// 检查无效字符
if (val1 == -1 || val2 == -1 ||
(input[i + 2] != '=' && val3 == -1) ||
(input[i + 3] != '=' && val4 == -1)) {
free(output);
*output_length = 0;
returnNULL;
}
// 将4个6位值合并为一个24位整数
unsignedint value = (val1 << 18) | (val2 << 12) | (val3 << 6) | val4;
// 从24位整数中提取3个8位字节
output[j] = (value >> 16) & 0xFF;
// 根据填充情况决定是否提取后两个字节
if (input[i + 2] != '=') {
output[j + 1] = (value >> 8) & 0xFF;
}
if (input[i + 3] != '=') {
output[j + 2] = value & 0xFF;
}
}
return output;
}
// 测试函数
void test_base64() {
// 测试数据
constchar *test_strings[] = {
"", "A", "AB", "ABC", "ABCD",
"Hello, World!", "Base64 encoding test",
"这是一个中文字符测试"
};
int num_tests = sizeof(test_strings) / sizeof(test_strings[0]);
for (int i = 0; i < num_tests; i++) {
constchar *original = test_strings[i];
printf("测试字符串: \"%s\"\n", original);
// 编码
char *encoded = base64_encode((constunsignedchar *)original, strlen(original));
if (encoded == NULL) {
printf("编码失败\n");
continue;
}
printf("编码结果: %s\n", encoded);
// 解码
size_t decoded_length;
unsignedchar *decoded = base64_decode(encoded, &decoded_length);
if (decoded == NULL) {
printf("解码失败\n");
free(encoded);
continue;
}
// 验证解码结果是否与原始一致
if (decoded_length == strlen(original) &&
memcmp(decoded, original, decoded_length) == 0) {
printf("验证成功: 解码结果与原始一致\n");
} else {
printf("验证失败: 解码结果与原始不一致\n");
printf("解码结果: ");
for (size_t j = 0; j < decoded_length; j++) {
printf("%c", decoded[j]);
}
printf("\n");
}
// 释放内存
free(encoded);
free(decoded);
printf("-------------------------\n");
}
}
int main() {
test_base64();
return0;
}

image
Base64编码的核心思想是将3字节的二进制数据转换为4字节的文本数据:
例如,"ABC"的编码过程:
// 编码表:64个可打印字符,顺序对应0-63
const char base64_encoding_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// 解码表:快速查找字符对应的数值,非Base64字符对应-1
const int base64_decoding_table[256] = { ... };
编码表是一个字符串,索引0-63分别对应Base64的64个字符。解码表是一个大小为256的数组(对应所有可能的ASCII值),通过字符的ASCII值作为索引,可以快速找到对应的数值,非Base64字符则对应-1。
// 计算编码后长度
size_t base64_encoded_length(size_t input_length) {
return (input_length + 2) / 3 * 4;
}
编码长度计算公式:(输入长度 + 2) / 3 * 4。加2是为了确保整数除法时能向上取整,例如输入长度为1时,(1+2)/3=1,1*4=4。
// 计算解码后长度
size_t base64_decoded_length(const char *input) {
size_t length = strlen(input);
size_t padding = 0;
// 检查填充的'='数量
if (length > 0 && input[length - 1] == '=') padding++;
if (length > 1 && input[length - 2] == '=') padding++;
return (length / 4) * 3 - padding;
}
解码长度计算公式:(输入长度 / 4) * 3 - 填充数。填充数是指末尾的'='字符数量,可能是0、1或2。
编码函数的核心步骤:
char *base64_encode(const unsigned char *input, size_t input_length) {
// 分配内存
size_t output_length = base64_encoded_length(input_length);
char *output = (char *)malloc(output_length + 1);
if (output == NULL) returnNULL;
// 处理每个3字节块
for (i = 0, j = 0; i < input_length; i += 3, j += 4) {
// 读取3个字节,不足补0
unsignedchar byte1 = input[i];
unsignedchar byte2 = (i + 1 < input_length) ? input[i + 1] : 0;
unsignedchar byte3 = (i + 2 < input_length) ? input[i + 2] : 0;
// 合并为24位整数
unsignedint value = (byte1 << 16) | (byte2 << 8) | byte3;
// 提取4个6位值并映射
output[j] = base64_encoding_table[(value >> 18) & 0x3F];
output[j + 1] = base64_encoding_table[(value >> 12) & 0x3F];
// 处理填充
output[j + 2] = (i + 1 < input_length) ?
base64_encoding_table[(value >> 6) & 0x3F] : '=';
output[j + 3] = (i + 2 < input_length) ?
base64_encoding_table[value & 0x3F] : '=';
}
output[output_length] = '\0';
return output;
}
解码函数的核心步骤:
unsigned char *base64_decode(const char *input, size_t *output_length) {
// 检查输入合法性
size_t input_length = strlen(input);
if (input_length % 4 != 0) {
*output_length = 0;
returnNULL;
}
// 分配内存
*output_length = base64_decoded_length(input);
unsignedchar *output = (unsignedchar *)malloc(*output_length);
if (output == NULL) {
*output_length = 0;
returnNULL;
}
// 处理每个4字符块
for (i = 0, j = 0; i < input_length; i += 4, j += 3) {
// 获取4个6位值
int val1 = base64_decoding_table[(unsignedchar)input[i]];
int val2 = base64_decoding_table[(unsignedchar)input[i + 1]];
int val3 = base64_decoding_table[(unsignedchar)input[i + 2]];
int val4 = base64_decoding_table[(unsignedchar)input[i + 3]];
// 检查无效字符
if (val1 == -1 || val2 == -1 ||
(input[i + 2] != '=' && val3 == -1) ||
(input[i + 3] != '=' && val4 == -1)) {
free(output);
*output_length = 0;
returnNULL;
}
// 合并为24位整数
unsignedint value = (val1 << 18) | (val2 << 12) | (val3 << 6) | val4;
// 提取3个字节
output[j] = (value >> 16) & 0xFF;
if (input[i + 2] != '=') {
output[j + 1] = (value >> 8) & 0xFF;
}
if (input[i + 3] != '=') {
output[j + 2] = value & 0xFF;
}
}
return output;
}
test_base64函数通过多个测试用例验证编码解码功能的正确性,包括空字符串、不同长度的字符串以及中文字符等。每个测试用例都会:
--完--
读到这里说明你喜欢本公众号的文章,欢迎 置顶(标星)本公众号 C语言中文社区,这样就可以第一时间获取推送了~
在本公众号,后台回复:1024 ,免费领取一份C语言学习大礼包