std::stoi可将十六进制字符串(如"1a"、"0xFF")转为十进制整数,需指定基数16;std::to_string不支持进制转换,应改用std::stringstream或C++20的std::format转回十六进制字符串。

用 std::stoi 和 std::to_string 转十六进制字符串为十进制整数
十六进制字符串(如 "1a"、"0xFF")转十进制整数,最常用的是 std::stoi,它支持指定进制。注意:它默认按十进制解析,必须显式传入 16 作为基数。
常见错误是忽略前缀处理或未捕获异常:
-
std::stoi("0xFF", nullptr, 16)正确,返回255;但std::stoi("0xFF")会按十进制解析,抛出std::invalid_argument - 字符串含空格或非法字符(如
"1g")会导致异常,建议用try/catch包裹 - 若输入可能带
"0x"或"0X"前缀,std::stoi能自动跳过(前提是基数设为0或16);设为16时仍会跳过前缀,但更安全的做法是先清理或统一用0基数让其自动识别
用 std::stringstream 或 std::format(C++20)转十进制整数为十六进制字符串
十进制整数转十六进制字符串,推荐两种方式:传统 std::stringstream(兼容 C++11+),或现代 std::format(C++20 起)。
std::stringstream 需配合 std::hex、std::uppercase、std::setfill 等操纵符:
立即学习“C++免费学习笔记(深入)”;
std::stringstream ss;
ss << std::hex << std::nouppercase << std::setfill('0') << std::setw(2) << 255;
std::string s = ss.str(); // 得到 "ff"关键点:
-
std::hex只影响后续整数输出,不改变流状态以外的任何东西 -
std::setw是**单次有效**的,下次输出需重新设置;std::setfill是持久的 - 若要大写(
"FF"),加std::uppercase;否则默认小写
C++20 可直接用 std::format,更简洁:
std::string s = std::format("{:x}", 255); // "ff"
std::string S = std::format("{:X}", 255); // "FF"
std::string p = std::format("{:02x}", 255); // "ff",但对 10 输出 "0a"处理无符号整数与溢出边界时的注意事项
十六进制常用于表示字节、内存地址等无符号场景,而 std::stoi 返回 int,容易溢出。比如解析 "FFFFFFFF"(32 位全 1)在 32 位系统上会触发 std::out_of_range。
正确做法取决于目标类型:
- 要转成
unsigned int:用std::stoul(unsigned long)或std::stoull(unsigned long long) - 要转成固定宽度类型如
uint32_t:先用std::stoul,再手动检查范围,或用std::from_chars(C++17,无异常、更快、支持指定进制且可校验截断) -
std::from_chars示例:uint32_t val; auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), val, 16); if (ec == std::errc()) { /* 成功 */ }它不跳过前缀,也不支持"0x"自动识别,需提前剥离
读写文件或二进制数据时别混淆“十六进制显示”和“真实字节”
新手常误以为把一个 uint8_t 值(如 255)格式化为 "ff" 就等于“存了十六进制”,其实这只是文本表示。真正写入二进制文件时,应写原始字节 \xff,而非两个字符 'f' 和 'f'。
所以:
- 日志/调试中用
std::format("{:02x}", byte)是为了人眼可读 - 网络协议或文件格式要求“十六进制编码字符串”(如 Base16 / hex encoding),则需对每个字节分别转两位十六进制字符,拼接起来——这不是进制转换,而是编码,得循环处理每个字节
- 反之,从 hex string 解码回字节数组,也不能用
std::stoi一次转完,而要每两个字符一组解析,例如"aabbcc"→{0xaa, 0xbb, 0xcc}
这些边界情况,不细看文档或不跑实际字节级测试,很容易出错。


















