最推荐使用 std::stod,它自动处理空格、符号、科学计数法并抛出明确异常;std::strtod 更底层但需手动判错;应避免 atof 和 std::stringstream。

直接用 std::stod 是最安全、最推荐的方式,C++11 起已标准化,能自动处理空格、符号、科学计数法,并抛出明确异常。
用 std::stod 转换(推荐)
这是 C++ 标准库提供的首选方法,底层调用 strtod 但封装更友好,支持异常控制和起始位置返回。
- 输入字符串开头可含空格或正负号,例如
" -123.45e2"可正确解析 - 遇到非法字符时,只转换前面合法部分,
idx输出参数会指出第一个未转换字符的位置 - 若整个字符串无效(如
"abc"或空串),抛出std::invalid_argument - 若数值溢出(超
double表示范围),抛出std::out_of_range
std::string s = " 3.14159e-2";
size_t idx;
try {
double d = std::stod(s, &idx);
if (idx != s.length()) {
// 注意:s 中还有未解析的尾部,比如 "1.23abc" → d=1.23,idx=3
}
} catch (const std::invalid_argument&) {
// 格式错误,如 "xyz"
} catch (const std::out_of_range&) {
// 溢出,如 "1e309"
}用 std::strtod(C 风格,需手动判错)
比 stod 更底层,不抛异常,靠返回值和 endptr 判断结果,适合嵌入式或禁用异常的环境。
- 必须检查
endptr是否移动 —— 若等于输入指针,说明一个字符都没转 - 需手动判断是否溢出:
errno == ERANGE,且返回值为HUGE_VAL或-HUGE_VAL - 不跳过首尾空格以外的内容,比如
"123 456"只转123,endptr指向空格
std::string s = "1.7976931348623157e308extra";
char* endptr;
errno = 0;
double d = std::strtod(s.c_str(), &endptr);
if (endptr == s.c_str()) {
// 完全没识别到数字
} else if (*endptr != '\0') {
// 有剩余未解析内容,如上面的 "extra"
} else if (errno == ERANGE && (d == HUGE_VAL || d == -HUGE_VAL)) {
// 溢出
}避免用 atof 或 std::stringstream
atof 完全不报错,非法输入一律返回 0.0,无法区分 "0" 和 "garbage";std::stringstream 性能差、语法冗长,且失败时需手动检查 failbit,容易漏判。
立即学习“C++免费学习笔记(深入)”;
-
atof("xyz")返回0.0,无任何提示 -
std::stringstream ss("123.45"); double d; ss >> d;后必须写if (ss.fail() || !ss.eof())才算完整,否则"123abc"会被静默接受为123.0
注意 locale 影响(小数点分隔符)
std::stod 和 std::strtod 默认使用 C locale,即小数点必须是英文句点 .。如果系统 locale 被设为德语(小数点用逗号 ,),它们仍按 C locale 解析,不会自动适配。
- 想支持本地化格式(如
"123,45"),不能依赖标准转换函数,需先替换逗号为点,或用std::use_facet<:num_get>>手动解析 - 跨平台分发时,尤其要注意 CI 环境或容器中 locale 是否被意外修改
真正难的不是选哪个函数,而是统一处理“部分有效”场景 —— 比如用户输入 "2.5px" 或 "-inf",是否接受?是否截断?这些逻辑必须在调用后立刻用 idx 或 endptr 显式检查,否则 bug 会藏得很深。











