推荐使用std::from_chars:它不抛异常、不分配内存、可精确控制解析范围,需手动处理前导空格和结尾'\0'问题,适合高性能与嵌入式场景。

字符数组转整数:直接用 atoi 最快但有陷阱
能转,但前提是字符数组以 '\0' 结尾且内容是合法十进制整数格式(可带正负号,不能含空格或字母)。atoi 不做错误检查,遇到非法字符就停在那儿,返回已解析的部分——比如 "123abc" 返回 123,"abc123" 返回 0,容易误判失败。
常见误用场景:
- 传入未初始化或没结尾
'\0'的数组 → 读越界,行为未定义 - 传入空指针 → 程序崩溃(
atoi(nullptr)是 UB) - 数值超出
int范围(如"2147483648")→ 溢出后结果不确定(不是固定返回INT_MAX或INT_MIN)
std::stoi 替代 atoi:更安全,但要注意异常
std::stoi 是 C++11 起推荐的替代方案,它会抛异常而不是静默失败。它要求输入是 std::string,所以得先构造字符串,或者用 std::string_view(C++17)避免拷贝。
关键点:
- 输入为空或全空白 → 抛
std::invalid_argument - 数值溢出 → 抛
std::out_of_range - 允许开头有空白,但只解析到第一个非法字符为止(和
atoi类似) - 支持指定进制,比如
std::stoi("ff", nullptr, 16)得255
示例:
char arr[] = " -42abc";
try {
std::string s(arr);
int n = std::stoi(s); // n == -42,不会报错
} catch (const std::exception& e) {
// 处理 invalid_argument 或 out_of_range
}
需要严格校验时:用 std::from_chars(C++17)
这是目前最轻量、最可控的方式,不抛异常、不分配内存、不跳过前导空格,纯 C 风格接口。适合嵌入式或高性能场景。
用法要点:
- 必须手动确保字符数组以
'\0'结尾,或传入明确的长度 - 返回值是结构体
std::from_chars_result,含ptr(指向首个未转换字符)和ec(错误码) -
ec == std::errc()表示完全成功;ec == std::errc::invalid_argument表示无有效数字;ec == std::errc::result_out_of_range表示溢出 - 它不忽略前导空格,所以
" 123"会直接失败 —— 需要自己跳过
示例:
char arr[] = "-12345";
int val;
auto res = std::from_chars(arr, arr + sizeof(arr) - 1, val);
if (res.ec == std::errc()) {
// 成功,val 已赋值
} else if (res.ec == std::errc::invalid_argument) {
// 没有可解析的数字
} else if (res.ec == std::errc::result_out_of_range) {
// 溢出
}
字符数组没以 '\0' 结尾?别硬传给 atoi
比如你从二进制协议里读了 4 字节数据到 char buf[4],内容是 {'1','2','3','4'},但它不是字符串——缺结尾 '\0'。这时直接传 buf 给 atoi 会继续往后读,直到撞上某个偶然的 '\0',结果不可控。
安全做法只有两个:
- 复制到带结尾的缓冲区:
char tmp[5] = {}; memcpy(tmp, buf, 4); int x = atoi(tmp); - 用
std::from_chars显式指定范围:std::from_chars(buf, buf + 4, x)
别用 std::string(buf) —— 它会按 C 字符串语义读到第一个 '\0',而你的数组里可能根本没有 '\0',导致越界。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











