std::stoi和std::to_string不支持任意进制互转,因二者仅单向固定进制转换;需手写解析(查表+溢出检查)和编码(除基取余+反转)实现源/目标进制双参数转换。

为什么不能直接用 std::stoi 或 std::to_string 做任意进制转换
这两个函数只支持 2–36 进制的字符串解析和格式化,但前提是目标进制是固定的、已知的——std::stoi 的第三个参数是 base,只能指定一个进制;它不接受“源进制 + 目标进制”双参数。一旦你要把一个 "1A"(十六进制)转成八进制字符串,就不能靠标准库单步完成。
更关键的是:标准库没有提供“任意进制 → 任意进制”的中间整数桥接接口。你必须自己把输入字符串按源进制解析成 unsigned long long(或大数),再按目标进制重新编码为字符串。
常见错误现象:std::stoi("1A", nullptr, 16) 能转出 26,但若目标进制是 8,你得自己写除 8 取余逻辑;有人误用 std::to_string(26) 得到 "26"(十进制字符串),不是八进制的 "32"。
怎么安全地把任意进制字符串转成整数(2–36)
核心是手写解析:遍历每个字符,查表映射为数值,累加计算 value = value * src_base + digit。注意边界检查——输入字符是否合法、结果是否溢出。
- 用
std::string查表比switch更简洁:"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",索引即数值 - 必须提前验证每个字符是否在前
src_base个字符内,否则返回错误(比如"8"在七进制里非法) - 溢出判断不能只靠
value > ULLONG_MAX / src_base,还要检查value * src_base + digit > ULLONG_MAX,建议用std::mul_overflow(C++23)或手动比较 - 负号要单独处理:只允许开头一个
'-',且仅当目标类型支持有符号时才保留
示例片段(无符号):
unsigned long long parse(const std::string& s, int src_base) {
unsigned long long res = 0;
size_t i = 0;
if (s[0] == '-') ++i; // 忽略负号,后续按需处理
const std::string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (; i = (size_t)src_base) throw std::invalid_argument("invalid digit");
if (res > ULLONG_MAX / src_base || res * src_base > ULLONG_MAX - pos)
throw std::overflow_error("overflow");
res = res * src_base + pos;
}
return res;
}
怎么把整数转回任意进制字符串(2–36)
经典“除基取余”,但要注意:0 要特判;余数映射回字符要用同一张表;结果是逆序,需反转。
- 目标进制为 1 时非法,但题目限定 2–36,可省略检查
- 如果原数是 0,循环不会执行一次,必须手动 push
'0' - 负数处理:先取绝对值转换,最后加 '-';但要注意
INT_MIN取反会溢出,所以推荐全程用无符号类型,输入时就分离符号 - 不要用
std::to_string拼接——它只生成十进制;必须用查表 +std::string::push_back
示例(假设 val 是非负 unsigned long long):
std::string to_base(unsigned long long val, int dst_base) {
if (val == 0) return "0";
std::string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string res;
while (val) {
res.push_back(digits[val % dst_base]);
val /= dst_base;
}
std::reverse(res.begin(), res.end());
return res;
}
组合起来实现完整转换函数,要注意什么
最终接口形如 std::string convert(const std::string& input, int from, int to),但它隐含几个容易被忽略的复杂点:
- 输入可能带空格或大小写混合,需提前
trim和std::toupper统一 -
from和to必须在 [2,36] 区间,否则抛异常——别默认接受 1 或 37 - 中间整数用
unsigned long long最多支持约 20 位十进制数;若输入是"ZZZZZZZZZZ"(36 进制),很快溢出;真要支持大数,得换boost::multiprecision或手写数组 - 没有标准方式表示负进制或浮点进制转换,本方案只处理整数部分
所以实际工程中,别硬扛超长输入。看到长度 > 15 且进制 ≥ 16,就该提示“可能溢出”,或直接切到大数库。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











