首选 std::stoi,但需 try-catch 处理 invalid_argument 和 out_of_range 异常;std::strtol 更可控,支持进制指定与解析位置检查;避免 atoi;C++20 推荐 std::from_chars,零开销但需手动处理空格和符号。

用 std::stoi 最直接,但要注意异常和截断
std::stoi 是 C++11 起标准库提供的首选方式,它把 std::string 转成 int,内部会跳过前导空格、识别正负号,并在首个非法字符处停止解析。
常见错误现象:传入空字符串、纯空格、非数字开头(如 "abc123")或超出 int 范围(如 "2147483648")时抛出 std::invalid_argument 或 std::out_of_range 异常。
实操建议:
- 务必用
try-catch包裹,尤其输入不可控时 - 如果只要开头数字(如
"123abc"想转成 123),std::stoi默认支持;但"abc123"会直接抛invalid_argument - 它不接受十六进制前缀(
"0x1F"),也不处理逗号分隔符
std::string s = " -42 ";
try {
int x = std::stoi(s); // x == -42
} catch (const std::invalid_argument& e) {
// 处理非数字内容
} catch (const std::out_of_range& e) {
// 处理溢出
}用 std::strtol 更底层,可控性更强
std::strtol 是 C 风格函数,需要先用 .c_str() 转换,但它允许你拿到解析结束位置、指定进制、且不抛异常——适合对性能或错误处理有明确要求的场景。
立即学习“C++免费学习笔记(深入)”;
关键差异:
-
std::strtol返回long,需手动截断到int并检查是否溢出 - 第二个参数
char** endptr可用于判断实际解析了多少字符(比如区分"123"和"123abc") - 第三个参数
base支持 0(自动识别0x/0)、2–36 进制
std::string s = "123abc";
char* end;
long val = std::strtol(s.c_str(), &end, 10);
if (*end != '\0') {
// 说明后面还有未解析字符,如 'a'
}
if (val < INT_MIN || val > INT_MAX) {
// 溢出,不能安全转为 int
}别用 atoi,它静默失败太危险
atoi 看起来简单,但遇到空字符串、全空格或非法输入时一律返回 0,且没有任何方式区分「真的就是 0」和「转换失败」。C++ 标准不推荐在新代码中使用。
典型陷阱:
-
atoi("")→ 0 -
atoi(" ")→ 0 -
atoi("xyz")→ 0 - 不报告错误,不设
errno(POSIX 下可能设,但不可靠)
除非你明确知道输入绝对合法,否则绕开它。
注意 C++20 的 std::from_chars:零开销、无异常、不分配内存
如果你用的是 C++20 或更高版本,std::from_chars 是目前最高效的选择。它不抛异常、不依赖 locale、不分配堆内存,且能精确告诉你解析停在哪一位。
但它只接受 std::string_view 或原始字符指针+长度,不自动跳过空格,也不处理符号——你需要自己预处理。
适用场景:高频数值解析(如日志解析、网络协议解包),且输入格式高度可控。
std::string s = "-42";
int value;
auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value);
if (ec == std::errc{}) {
// 成功
} else if (ec == std::errc::invalid_argument) {
// 首字符就非法(如空串、空格开头)
} else if (ec == std::errc::result_out_of_range) {
// 溢出
}C++ 字符串转整型没有“一劳永逸”的写法。选 std::stoi 图省事但得兜住异常;选 std::strtol 要多写几行但逻辑清晰;std::from_chars 性能最好,可一旦要处理空格或符号就得自己补逻辑——最容易被忽略的,其实是“输入到底可不可信”这个前提。











