首选 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("") → 0atoi(" ") → 0atoi("xyz") → 0errno(POSIX 下可能设,但不可靠)除非你明确知道输入绝对合法,否则绕开它。
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 性能最好,可一旦要处理空格或符号就得自己补逻辑——最容易被忽略的,其实是“输入到底可不可信”这个前提。