正确做法是按每两个字符切片并校验:先去空格、检查偶数长度,再两两截取用std::stoul解析为0~0xff范围内的字节存入vector。

字符串转十六进制字节数组的常见错误
直接用 std::stoi(s, nullptr, 16) 解析整个字符串,会失败——它只处理单个整数,不是字节序列。更常见的是把 "A1B2C3" 当成一个大整数解析,结果溢出或截断。还有人用 sscanf 循环读,但没处理好长度校验和大小端,导致末尾字节错位或越界。
安全解析:按每两个字符切片 + 校验
十六进制字符串必须是偶数长度,每个字节对应两个字符(如 "FF" → 0xFF)。先检查长度,再两两截取,用 std::stoul 带基数解析,比 std::stoi 更稳妥(避免有符号溢出)。
关键点:
- 字符串去空格:用
std::erase_if(str, ::isspace)(C++20)或手动遍历过滤 - 长度校验:若
str.length() % 2 != 0,直接报错或补前导零(按需) - 每对字符调用
std::stoul(sub, nullptr, 16),结果必须 ≤ 0xFF,否则非法字符(如"G1") - 存入
std::vector<uint8_t></uint8_t>,不是int或char(避免符号扩展问题)
兼容旧标准的 C++11 写法示例
不用 C++20 的 erase_if,也不依赖异常做流程控制(比如不靠 std::stoul 抛异常来判断非法字符),可以手动遍历解析:
std::vector<uint8_t> hexstr_to_bytes(const std::string& s) {
std::vector<uint8_t> out;
out.reserve((s.size() + 1) / 2);
for (size_t i = 0; i = s.size()) break; // 自动跳过奇数末尾
uint8_t hi = hex_char_to_val(s[i]);
uint8_t lo = hex_char_to_val(s[i + 1]);
if (hi == 0xFF || lo == 0xFF) continue; // 跳过非法字符
out.push_back((hi
<p>其中 <code>hex_char_to_val</code> 是个查表函数(<code>'0'→0</code>, <code>'a'→10</code>, <code>'F'→15</code>),大小写不敏感,返回 <code>0xFF</code> 表示非法。</p>
<h3>注意大小写、前缀与编码边界</h3>
<p>真实数据常带 <code>"0x"</code> 前缀(如 <code>"0xA1B2"</code>),需提前去掉;也有人混用大小写(<code>"a1B2"</code>),所以解析函数必须统一转小写或查表兼容。另外,如果输入来自网络或文件,要考虑 BOM 或 UTF-8 非 ASCII 字符污染——哪怕看起来是十六进制,开头几个字节可能是 <code>EF BB BF</code>,得先剥离。</p>
<p>最易被忽略的是:解析后数组长度 ≠ 原字符串长度 / 2,当存在空格、换行、前缀或非法字符时,必须显式定义“容错策略”——是跳过?报错?还是终止?没有默认正确答案,取决于你的协议规范。</p></uint8_t></uint8_t>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











