std::hex 是流操纵符,仅影响整数输出格式,无法直接用于字符串 hex 编码;需手动实现字符转换,且要求字符串长度为偶数、字符合法。

为什么不能直接用 std::hex 做字符串 hex 编码?
因为 std::hex 是流操纵符,只影响整数输出格式,对 std::string 无作用;直接 std::ostringstream 能编码,结果只是把字符串地址或乱码塞进去。
真正要做的是:把每个 char 当作无符号字节(0–255),转成两位十六进制字符(如 '\x41' → "41"),拼接成新字符串。关键点在于强制类型转换和查表/计算效率。
- 必须将
char转为unsigned char,否则负值(如0xFF)会被解释为 -1,再转int后仍是负数,std::hex输出不可控 - 避免用
std::stringstream逐字符 - 推荐预分配目标缓冲区:输入长度
n→ 输出长度2*n
手写高效 hex 编码:查表法比 std::sprintf 快 3–5 倍
查表法用两个静态 const 数组分别存 0–9、A–F 的 ASCII 字符,每个字节拆高低 4 位,查两次表。比调用 sprintf 或 std::format(C++20)更轻量、确定性高、无异常风险。
static constexpr char HEX_CHARS[] = "0123456789abcdef";
std::string hex_encode(const std::string& s) {
std::string out;
out.reserve(s.size() * 2);
for (unsigned char c : s) {
out.push_back(HEX_CHARS[c >> 4]);
out.push_back(HEX_CHARS[c & 0x0F]);
}
return out;
}
-
c >> 4取高 4 位,c & 0x0F取低 4 位,位运算比除法/取模快 - 用
unsigned char遍历确保符号安全;若输入是std::string,其value_type是char,需显式转换 - 不建议用
std::to_chars(C++17)做单字节转 hex,它只为整数设计,且不支持直接填入 string buffer
hex 解码(还原)必须校验输入合法性,否则崩溃或越界
解码比编码更易出错:输入可能含非 hex 字符(空格、换行、大小写混用)、长度为奇数、甚至 null 字节。不校验就直接解,out[i/2] |= ... 类操作会越界或逻辑错。
标准做法是先跳过空白(可选),然后两两一组解析;每组必须是 [0–9a–fA–F],否则返回失败(如抛异常或返回空 string)。
std::string hex_decode(const std::string& s) {
std::string out;
out.reserve(s.size() / 2);
for (size_t i = 0; i = s.size()) return {}; // 长度奇数,非法
unsigned char hi = hex_char_to_nibble(s[i]);
unsigned char lo = hex_char_to_nibble(s[i + 1]);
if (hi > 15 || lo > 15) return {}; // 非法字符
out.push_back((hi
-
hex_char_to_nibble应用查表或 switch,返回 0–15 或 255 表示非法;别用std::stoi或std::strtol,太重 - 注意大小写:
'A'和'a'都应映射到 10;查表时可用 256 元素数组,索引为static_cast<unsigned char>(c)</unsigned> - 不建议跳过所有空白——某些协议(如 PEM)要求严格格式,盲目 strip 可能破坏数据边界
C++20 std::format 能否替代手写?目前不推荐用于高频场景
std::format("{:02x}", static_cast<int>(c))</int> 看起来简洁,但实测在循环中比查表慢 2–4 倍,且 C++20 支持度仍有限(MSVC 19.30+、GCC 13+、Clang 15+ 才完整)。更重要的是:它默认小写、无零填充控制、无法避免临时 string 构造。
- 若项目已强制 C++20 且吞吐量不高(如配置文件解析),可用,但要加
static_cast<unsigned int></unsigned>防符号扩展 - 生产级网络库或加密模块(如 base64/hex 编解码器)几乎都手写,因可控性与性能压倒便利性
- 第三方库如
absl::HexStringToBytes或boost::algorithm::hex可用,但引入依赖前需确认其是否做输入校验、是否支持 inplace 操作
真正难的不是写对,而是让编码/解码在任意输入下都不崩、不漏、不慢——边界检查、无符号处理、内存预分配,这三处漏掉任何一项,上线后都可能变成偶发 crash 或安全漏洞。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











