std::stoi最直接但会抛异常,std::from_chars是C++17推荐的无异常方案,支持精确校验;转浮点数应避免std::stof,优先用std::from_chars或sscanf配合%n严格匹配。

用 std::stoi 转整数最直接,但会抛异常
多数情况下,std::stoi 是首选:它把 std::string 转成 int,自动跳过开头空白、识别正负号和进制前缀(如 "0x")。但它遇到非法字符(比如 "123abc")或溢出时,会抛 std::invalid_argument 或 std::out_of_range 异常。
实操建议:
- 如果输入可控(如配置文件里确定是纯数字),直接用
std::stoi最简洁 - 如果输入来自用户或外部接口,必须加
try/catch,否则程序可能崩溃 -
std::stoi只读到第一个非法字符为止——std::stoi("42px")返回42,不报错;但std::stoi("px42")就抛std::invalid_argument - 需要指定进制时,传第三个参数:
std::stoi("1010", nullptr, 2)→10
std::from_chars 是 C++17 推荐的无异常方案
如果你用的是 C++17 或更新标准,std::from_chars 是更现代、更轻量的选择。它不抛异常、不依赖 locale、不分配内存,性能好,且能精确告诉你转换停在哪——这对校验输入是否“完全合法”很关键。
常见用法:
立即学习“C++免费学习笔记(深入)”;
- 先声明目标变量(如
int value),再调用:auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value) -
ec == std::errc{}表示成功;ec == std::errc::invalid_argument表示全无效;ec == std::errc::result_out_of_range表示溢出 - 若
ptr != str.data() + str.size(),说明后面还有未解析字符(如"123abc"中ptr指向'a'),可据此判断是否“严格全数字” - 注意:
std::from_chars不支持进制参数,只处理十进制、十六进制(带0x)、八进制(带0)等默认格式
转浮点数别用 std::stof 做精度校验
std::stof、std::stod 看似顺手,但它们对输入容忍度过高:比如 std::stof("1.23e+4xyz") 成功返回 12300.0,而 "inf"、"nan" 也被接受。这在金融、协议解析等场景容易埋雷。
更稳妥的做法:
- 先用
std::from_chars(C++17+)尝试解析——它对浮点也支持,且返回指针位置,可严格比对是否整个字符串都被消费 - 若需兼容旧标准,可用
std::sscanf配合 %n 获取已读字节数:float v; int n; if (sscanf(s.c_str(), "%f%n", &v, &n) == 1 && n == (int)s.size())—— 这样才能确认无残留字符 - 避免用
atof:它遇到错误只返回 0,无法区分"0"和"abc"
小心 C 风格函数的全局状态和线程安全
像 strtol、strtod 这类 C 函数,虽然灵活(支持 base、可获取结束位置),但要注意:errno 是全局变量,多线程下需手动清零并检查;而且它们不处理 Unicode 或宽字符,std::string 含非 ASCII 字节时行为未定义。
使用前提:
- 只在 C++98/03 环境或与 C 库深度耦合时考虑
- 每次调用前必须设
errno = 0,之后检查errno == ERANGE判断溢出 - 用
char** endptr参数拿到解析终点,再手动比对长度,才能模拟std::from_chars的“全匹配”逻辑 - 别混用
std::string和std::wstring:C 函数不认wchar_t*,强转会出问题
真正麻烦的不是“怎么转”,而是“怎么知道转得对不对”。尤其当字符串来自不可信来源时,std::from_chars 的 ptr 输出和 errc 分类,是最容易被忽略也最关键的验证环节。


















