c++中如何将string转换为int_c++字符串转整型常用方法

std::stoi最常用但非法输入抛异常致崩溃;std::from_chars无异常、高性能但不跳空白;atoi无错误反馈且空指针导致未定义行为;处理空格需手动trim或用stringstream。

std::stoi 用法与常见崩溃原因

直接调用 std::stoi 是最常用的方式,但它在输入非法时会抛出 std::invalid_argumentstd::out_of_range 异常,不加捕获会导致程序终止。

  • 空字符串、纯空白、非数字前缀(如 "abc123")触发 std::invalid_argument
  • 超出 int 表示范围(如 "2147483648")触发 std::out_of_range
  • 它默认按十进制解析,不支持前导 0x0 自动识别进制
try {
    int x = std::stoi("123");
} catch (const std::invalid_argument&) {
    // 处理非数字内容
} catch (const std::out_of_range&) {
    // 处理溢出
}

std::from_chars 避免异常且性能更高

std::from_chars 是 C++17 引入的无异常、零分配方案,适合高频或性能敏感场景。它返回一个 std::from_chars_result 结构体,需手动检查结果。

  • 不抛异常,仅通过 ec(error code)和 ptr(解析结束位置)判断成败
  • 支持指定进制,例如 std::from_chars(s.data(), s.data() + s.size(), value, 10)
  • 跳过前导空白?不支持 —— 它严格从首字符开始," 123" 会被判为失败
std::string s = "456";
int value;
auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value);
if (ec == std::errc()) {
    // 解析成功,value 已赋值
} else if (ec == std::errc::invalid_argument) {
    // 无有效数字
} else if (ec == std::errc::result_out_of_range) {
    // 溢出
}

atoi 不推荐用于新代码

atoi 来自 C 标准库,行为简单粗暴:遇到非法字符就停止并返回 0,无法区分 "0""""abc" 这三者。没有错误反馈机制,极易引入隐蔽 bug。

  • 传入空指针直接未定义行为(通常 crash)
  • 不检查溢出,超范围时结果是实现定义的(常见为 INT_MAXINT_MIN
  • 不能指定进制,始终按十进制解析
// 危险示例:以下三者都返回 0,但含义完全不同
atoi("");      // 0 —— 空串
atoi("0");      // 0 —— 合法零
atoi("xyz");    // 0 —— 完全非法

处理带空格或前后缀的 string

如果原始 std::string 可能含前导/尾随空白(如用户输入、文件读取),std::stoistd::from_chars 都不自动 trim。必须先清理或手动跳过。

  • s.find_first_not_of(" \t\n\r\f\v") 找起始位置,再用 s.find_last_not_of(" \t\n\r\f\v") 找结束位置
  • 或用 std::stringstream(较重,但自动跳过空白):ss >> value,再检查 ss.fail() 和是否还有剩余字符
  • std::from_chars 若想支持空格,得自己截取子串再调用,别试图传入未 trim 的原始指针

真正难的不是转换本身,而是你是否清楚输入来源的格式边界 —— 比如日志行里提取数字,可能混着括号、逗号、单位符号,这时候光靠 stoi 就不够用了。