atoi和atof不检查错误、遇非法字符即停、空指针/空字符串行为未定义;推荐用std::stoi/stod(异常+位置反馈)或C++17的std::from_chars(零开销+错误码)。

atoi 和 atof 的基本行为与限制
atoi 和 atof 是 C 标准库()中用于将 C 风格字符串(const char*)转为整数和浮点数的函数。它们不进行错误检查,遇到非法字符就立刻停止解析,且对空指针或空字符串行为未定义(实际常导致崩溃或返回 0)。
-
atoi("123abc")返回123,静默忽略"abc" -
atof(" -45.67e2")返回-4567.0,能处理空格、符号、科学计数法 -
atoi("")或atoi(nullptr)是未定义行为,不能依赖返回值 - 两者都不设置
errno,无法区分 “0”、“0x0”、“abc” 这些都返回 0 的情况
替代方案:用 std::stoi / std::stod 更安全
C++11 起推荐用 std::stoi 和 std::stod(在 中),它们接受 std::string,支持异常报告,并能返回解析结束位置。
char buf[] = "42hello";
std::string s(buf);
try {
size_t pos;
int i = std::stoi(s, &pos); // i == 42, pos == 2
if (pos != s.length()) {
// 有未解析的尾部,如 "hello"
}
} catch (const std::invalid_argument&) {
// 输入根本不是数字,如 "xyz"
} catch (const std::out_of_range&) {
// 溢出,如 "999999999999999999999"
}
- 必须传入非空
std::string,空字符串会抛std::invalid_argument -
&pos参数可选,但强烈建议使用,否则无法知道是否全串被成功解析 - 不接受 C 风格字符串直接调用,需先构造
std::string(或用std::string_view+ C++17 后的std::from_chars)
高性能场景:用 std::from_chars(C++17)
如果字符数组已知长度、追求零分配和无异常,std::from_chars 是最优解。它工作在原始内存上,不构造对象,也不抛异常,只通过返回码指示结果。
#includechar buf[] = "12345.6789end"; int i; auto [p, ec] = std::from_chars(buf, buf + 5, i); // 解析前5字符 if (ec == std::errc{}) { // 成功,i == 12345,p 指向 buf+5 } else if (ec == std::errc::invalid_argument) { // 无有效数字 } else if (ec == std::errc::result_out_of_range) { // 溢出 }
- 仅支持固定进制(
stoi可设 base=16,from_chars不行) - 浮点类型需用
std::from_chars(..., double&),但不支持科学计数法("1e3"会被截断) - 要求编译器支持 C++17 且标准库实现完整(GCC 11+/Clang 12+/MSVC 2019 16.8+)
常见误用与踩坑点
直接把 直接把 std::vector 或局部 char buf[32] 的 .data() / 数组名传给 atoi,却忘了确保末尾有 ',会导致越界读取。std::vector 或局部 char buf[32] 的 .data() / 数组名传给 atoi,却忘了确保末尾有 '\0',会导致越界读取。
立即学习“C++免费学习笔记(深入)”;
-
char buf[4] = {'1','2','3'};——buf[3]未初始化,atoi(buf)行为未定义 -
std::vector——v = {'4','5','6'}; v.data()没有结尾'\0',不能直接喂给atoi - 用
atoi解析用户输入或配置文件内容,结果是 0 却不检查是否真为零值还是解析失败 - 在嵌入式或信号处理等禁止异常环境中,误用
std::stoi而没做noexcept替代设计
字符数组转数字这件事,关键不在“怎么转”,而在“怎么确认转对了”。atoi/atof 的静默失败特性,在现代 C++ 工程里基本只该出现在兼容旧代码或极端性能敏感的内联汇编边界处。











