std::to_chars比sprintf快因省去格式解析、locale查询和内存分配,但需手动管理缓冲区、截断和错误码;它不写'\0'、不检查空指针、不扩容,仅按给定范围写入,失败时设ec为value_too_large且ptr等于last。

std::to_chars 确实比 sprintf 快,但快不是白来的——它快在彻底甩掉了格式解析、locale 查询和内存分配这三座大山;代价是你得自己管缓冲区、自己截长度、自己处理错误码。
为什么 std::to_chars 不崩溃但结果无效?
因为 std::to_chars 从不写 \0,也不检查空指针,更不会帮你扩容。它只按你给的 [first, last) 范围硬写,写不完就设 ec == std::errc::value_too_large,然后返回 ptr == last。
- 常见错误:传
buf + 10给一个可能写 24 字符的double,result.ec报错但被忽略,后续用std::string(buf)就读到未初始化内存 - 整数缓冲区最小安全长度:
std::numeric_limits<int64_t>::digits10 + 2</int64_t>(负号+结尾预留)→ 实际要 20 字节 - 浮点数缓冲区最小安全长度:
std::numeric_limits<double>::max_digits10 + 2</double>→ 至少 19 字节,建议直接开char buf[32] - 永远别用
strlen(buf)算长度——它找\0,而std::to_chars根本不写
std::to_chars 的浮点数精度控制到底行不行?
不行。std::to_chars 的 precision 参数在 C++17 中未被实现支持,传进去也当没传。它只保证 round-trip 正确性:float 输出最多 9 位有效数字,double 最多 17 位——这是 IEEE-754 十进制表示的理论下界,不是你能调的“小数点后几位”。
- 想固定 2 位小数?
std::to_chars不是工具,换fmt::format("{:.2f}", x)或退回去用sprintf(注意线程安全) -
std::chars_format::fixed只切换格式(禁用科学计数法),不控精度;general和scientific同理 - 数值大小影响实际字符数:1e-100 会走
e-100形式,比 123.45 多占至少 5 字符
缓冲区太小的典型错误现象
不是段错误,也不是断言失败,而是静默返回错误码——result.ec == std::errc::value_too_large,同时 result.ptr == last。如果你只检查 ptr 是否移动,或压根不看 ec,就等于把失败当成功用了。
- 对
int32_t,最坏情况是-2147483648→ 需要 11 字节;开char buf[10]必然失败 - 对
double,std::to_chars(buf, buf + 16, 3.14)很可能溢出,因 16 字节不够存符号、小数点、指数部分 - 错误处理必须显式:if (result.ec != std::errc{}) { /* handle */ },不能只靠
if (result.ptr != buf) - 不要依赖编译器警告——这个错误在运行时才暴露,且无 UB,极难调试
真正容易被忽略的是:它不兼容 locale,永远输出英文小数点和 e,和 sprintf 在德语/法语环境下行为天然不等价;如果你需要本地化格式,std::to_chars 就不该出现在你的调用栈里。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











