url编码的“完全双向”指encode后字符串能精确还原任意字节序列(含\0、控制字符、非utf-8数据),要求输入按const unsigned char*+size_t处理,编码将0–255字节全转%xx,解码严格解析%ab为0xab,非法序列不静默忽略。

什么是URL编码的“完全双向”?
所谓完全双向,是指 encode 后的字符串能被 decode 精确还原为原始字节序列,且对任意 std::string(含 null 字节、控制字符、非 UTF-8 二进制数据)都成立。这和常见“只处理 ASCII 子集”的简易实现有本质区别——那些实现会丢弃或误解释 \0、\x01、\xFF 等字节。
C++ 中必须用 raw 字节流,不能依赖 std::string 的文本语义
std::string 在 C++ 中本质是字节容器,不是文本容器。只要不把它当 UTF-8 字符串用(比如不调用 .c_str() 后传给 libc 函数),它完全可以安全存 \0 和任意字节。URL 编码操作对象就是字节,不是字符。
- 输入必须按
const unsigned char*+size_t处理,避免隐式转换丢失\0 - 编码时:每个字节(0–255)都转成
%XX格式,包括空格(' '→%20)、斜杠('/'→%2F)、甚至\0(→%00) - 解码时:遇到
%AB必须严格解析为字节0xAB;非法格式(如%GZ、%结尾)应设为错误或跳过,不能静默忽略 - 不要用
std::stringstream或std::hex做单字节转换——它们默认带符号扩展,(char)0xFF可能变成-1,再转十六进制就错
encode_url 和 decode_url 的最小可靠实现
以下函数不依赖 Boost 或第三方库,仅用标准 C++11:
std::string encode_url(const std::string& s) {
std::string out;
out.reserve(s.size() * 3);
for (unsigned char c : s) {
if ((c >= 'A' && c = 'a' && c = '0' && c > 4];
out += "0123456789ABCDEF"[c & 0xF];
}
}
return out;
}
<p>std::string decode_url(const std::string& s) {
std::string out;
out.reserve(s.size());
for (size_t i = 0; i ((hi </p><p>int hex_digit(char c) {
if (c >= '0' && c = 'A' && c = 'a' && c </p><p>注意:<code>encode_url</code> 中保留的字符集严格按 RFC 3986 的 “unreserved” 字符定义;<code>decode_url</code> 对非法 <code>%</code> 序列不做修复,直接透传原字符——这是防止歧义的合理策略。</p><h3>容易踩的坑:空字节、locale、以及 std::string::data() 的陷阱</h3><p>常见错误是把 <code>std::string</code> 当作 C 风格字符串用:</p>
-
s.c_str()返回的指针在遇到\0时就截断,导致后续字节全丢 -
s.data()在 C++11 中不保证以\0结尾,但长度正确;C++17 起data()和c_str()行为一致,仍需配合size()使用 - 某些 locale-aware 的
std::toupper或流操作会在非 ASCII 字节上出错,URL 编码必须无 locale - 如果原始数据来自文件读取或网络接收,确认你拿到的是原始字节——别用
std::ifstream默认的 text mode,要用std::ios::binary
真正需要双向保真时,std::string 是最轻量又足够可靠的载体;换用 std::vector<uint8_t></uint8_t> 也行,但接口适配成本更高。关键不在容器类型,而在全程绕过任何文本解释逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











