C++中如何实现Hex与Text模式Base64编码结果互转
C++ 实现Base64两种编码模式对齐方案
问题背景
开发对接多接口时会遇到Base64编码逻辑不一致的问题:两个对接API分别采用Hex模式、Text模式处理Base64编码,需要对齐编码逻辑保证跨接口结果统一。
两种模式对相同输入字符串的编码结果差异如下:
fb95 <- HEX -- BASE64-> +5U= fb95 <- TEXT -- BASE64-> ZmI5NQ==
两种模式的核心差异:
- Text模式:直接取输入字符串每个字符的ASCII字节作为Base64编码的输入字节流
- Hex模式:先将输入的十六进制字符串按每2个字符解析为1个原始字节,再将解析得到的字节流作为Base64编码的输入源
待实现目标
满足以下任意一种转换即可实现逻辑对齐:
- 将
std::string text("fb95");转换为Hex模式要求的原始字节形式,经Base64编码后得到结果+5U= - 将Text模式输出的Base64结果
std::string b64("ZmI5NQ==");直接转换为Hex模式对应的Base64结果+5U=
可行实现方案
两种目标本质逻辑相通,核心是先完成十六进制字符串到原始字节流的解析,再对字节流做标准Base64编码即可,以下是无第三方依赖的标准C++实现:
首先实现通用工具函数:
#include <string> #include <stdexcept> #include <cstdint> #include <cstring> // 十六进制字符转对应数值 inline uint8_t hex_char_to_val(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return 10 + c - 'a'; if (c >= 'A' && c <= 'F') return 10 + c - 'A'; throw std::invalid_argument("invalid hex character"); } // 十六进制字符串转原始字节流 std::string hex_str_to_bytes(const std::string& hex_str) { if (hex_str.size() % 2 != 0) { throw std::invalid_argument("hex string length must be even"); } std::string res; res.reserve(hex_str.size() / 2); for (size_t i = 0; i < hex_str.size(); i += 2) { uint8_t high = hex_char_to_val(hex_str[i]); uint8_t low = hex_char_to_val(hex_str[i+1]); res.push_back(static_cast<char>((high << 4) | low)); } return res; } // 标准Base64编码表 const char BASE64_TABLE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // 原始字节流转标准Base64字符串 std::string bytes_to_base64(const std::string& bytes) { std::string res; size_t len = bytes.size(); res.reserve((len + 2) / 3 * 4); for (size_t i = 0; i < len; ) { uint32_t octet_a = i < len ? static_cast<uint8_t>(bytes[i++]) : 0; uint32_t octet_b = i < len ? static_cast<uint8_t>(bytes[i++]) : 0; uint32_t octet_c = i < len ? static_cast<uint8_t>(bytes[i++]) : 0; uint32_t triple = (octet_a << 16) | (octet_b << 8) | octet_c; res.push_back(BASE64_TABLE[(triple >> 18) & 0x3F]); res.push_back(BASE64_TABLE[(triple >> 12) & 0x3F]); res.push_back(BASE64_TABLE[(triple >> 6) & 0x3F]); res.push_back(BASE64_TABLE[triple & 0x3F]); } // 补末尾等号 if (len % 3 == 1) { res[res.size()-1] = '='; res[res.size()-2] = '='; } else if (len % 3 == 2) { res[res.size()-1] = '='; } return res; } // 标准Base64字符串解码为原始字节流(用于方案2) std::string base64_to_bytes(const std::string& b64_str) { static int8_t rev_table[256]; static bool table_init = false; if (!table_init) { memset(rev_table, -1, sizeof(rev_table)); for (int i = 0; i < 64; i++) { rev_table[static_cast<uint8_t>(BASE64_TABLE[i])] = i; } table_init = true; } std::string res; size_t len = b64_str.size(); res.reserve(len / 4 * 3); for (size_t i = 0; i < len; ) { uint32_t sextet_a = b64_str[i] == '=' ? 0 & i++ : rev_table[static_cast<uint8_t>(b64_str[i++])]; uint32_t sextet_b = b64_str[i] == '=' ? 0 & i++ : rev_table[static_cast<uint8_t>(b64_str[i++])]; uint32_t sextet_c = b64_str[i] == '=' ? 0 & i++ : rev_table[static_cast<uint8_t>(b64_str[i++])]; uint32_t sextet_d = b64_str[i] == '=' ? 0 & i++ : rev_table[static_cast<uint8_t>(b64_str[i++])]; uint32_t triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d; if (sextet_c != -1) res.push_back(static_cast<char>((triple >> 16) & 0xFF)); if (sextet_d != -1) res.push_back(static_cast<char>((triple >> 8) & 0xFF)); } return res; }
方案1实现(原始文本转Hex模式Base64)
直接将输入的文本作为十六进制字符串解析为字节流,再做Base64编码即可:
std::string text_to_hex_b64(const std::string& text) { std::string bytes = hex_str_to_bytes(text); return bytes_to_base64(bytes); } // 测试:传入"fb95",返回结果为"+5U="
方案2实现(Text模式Base64转Hex模式Base64)
先将Text模式的Base64解码为原始ASCII字节流(即原始输入的十六进制字符串),再复用方案1的逻辑即可:
std::string text_b64_to_hex_b64(const std::string& text_b64) { std::string origin_text = base64_to_bytes(text_b64); return text_to_hex_b64(origin_text); } // 测试:传入"ZmI5NQ==",返回结果为"+5U="
注意:如果项目中已经引入了OpenSSL、Boost等自带Base64、Hex编解码能力的库,可以直接复用库的对应接口替换上述自实现的工具函数,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Szymon Ożóg
相关产品推荐
相关产品推荐

