首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >企业级开发 | C语言实现base64编码解码 | 附完整源码

企业级开发 | C语言实现base64编码解码 | 附完整源码

作者头像
C语言中文社区
发布2025-10-11 13:27:48
发布2025-10-11 13:27:48
2000
举报
文章被收录于专栏:C语言中文社区C语言中文社区

推荐阅读

优化C语言代码的11种实用方法

一位老程序员的忠告:别想着靠技术生存一辈子

附完整源码 | C语言设计跨平台日志库|企业级开发

一文搞懂C语言中的“栈溢出”和“堆溢出”,全网最通俗的解释

正文

Base64是一种常见的编码方式,用于将二进制数据转换为可打印的ASCII字符,广泛应用于网络传输、数据存储等场景。本文将详细讲解一个用C语言实现的Base64编码解码程序。

程序整体结构

我们的程序包含以下几个主要部分:

  • 编码表和解码表的定义
  • 计算编码/解码后长度的函数
  • 编码函数
  • 解码函数
  • 测试函数和主函数

下面是完整的实现代码:

代码语言:javascript
复制
#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
image

image

代码详解

1. Base64编码原理

Base64编码的核心思想是将3字节的二进制数据转换为4字节的文本数据:

  • 将3个8位(共24位)的二进制数据分成4个6位的组
  • 每个6位的组对应0-63之间的一个数值
  • 每个数值通过编码表映射为一个可打印字符
  • 如果输入数据不是3的倍数,用=符号填充

例如,"ABC"的编码过程:

  • A(01000001) B(01000010) C(01000011)
  • 分为4个6位组:010000 010100 001001 000011
  • 对应数值:16 20 9 3
  • 编码结果:QUJD

2. 编码表和解码表

代码语言:javascript
复制
// 编码表: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。

3. 长度计算函数

代码语言:javascript
复制
// 计算编码后长度
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。

代码语言:javascript
复制
// 计算解码后长度
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。

4. 编码函数

编码函数的核心步骤:

  1. 计算输出长度并分配内存
  2. 每次处理3个输入字节
  3. 将3个字节合并为24位整数
  4. 拆分为4个6位值,映射到编码表
  5. 处理填充情况
代码语言:javascript
复制
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;
}

5. 解码函数

解码函数的核心步骤:

  1. 检查输入合法性(长度是否为4的倍数)
  2. 计算输出长度并分配内存
  3. 每次处理4个输入字符
  4. 从解码表获取对应数值,检查有效性
  5. 合并为24位整数,提取3个字节
  6. 根据填充情况决定提取字节数
代码语言:javascript
复制
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;
}

6. 测试函数

test_base64函数通过多个测试用例验证编码解码功能的正确性,包括空字符串、不同长度的字符串以及中文字符等。每个测试用例都会:

  1. 对原始字符串进行编码
  2. 对编码结果进行解码
  3. 比较解码结果与原始字符串是否一致

--完--

读到这里说明你喜欢本公众号的文章,欢迎 置顶(标星)本公众号 C语言中文社区,这样就可以第一时间获取推送了~

在本公众号,后台回复:1024 ,免费领取一份C语言学习大礼包

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

本文分享自 C语言中文社区 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 推荐阅读
  • 正文
    • 程序整体结构
    • 测试结果
    • 代码详解
      • 1. Base64编码原理
      • 2. 编码表和解码表
      • 3. 长度计算函数
      • 4. 编码函数
      • 5. 解码函数
      • 6. 测试函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档