std::to_chars 转数字最快但需手动管理缓冲区,buf[24]适配int64_t,buf[32]适配double;返回ptr指向末字符后一位置,安全长度为result.ptr - buf,构造string须用该长度而非strlen或默认构造。

std::to_chars 是目前 C++ 标准库中数字转字符串的最快路径,但它的性能优势只在你避开 std::string 构造、复用缓冲区、且不依赖浮点精度控制时才真实存在;一旦传错缓冲区大小、忽略返回值或误当 C 字符串用,实测吞吐可能比 sprintf 还低。
std::to_chars 缓冲区大小必须手动算准,不能靠猜
传小了不会崩溃,但会静默返回 std::errc::value_too_large,后续用 result.ptr 构造字符串就拿到半截内容——线上日志字段突然变短、序列化 JSON 键名截断,极难定位。
- int64_t 最坏情况是
"-9223372036854775808"(20 字节),建议固定用char buf[24],留出符号、进制切换或未来扩展余量 - double 不是固定长度:
DBL_MIN可能输出"2.2250738585072014e-308"(24 字符),C++17 要求至少std::numeric_limits<double>::max_digits10 + 2</double>(19 字节),但实践中char buf[32]更稳妥 - 别用
sizeof("123")或硬写[16]——它不含负号逻辑,也不防科学计数法、次正规数或1e-100类长格式 - 别对
std::string::data()调用resize()后直接传:resize 不保证末尾为'\0',而std::to_chars从不写终止符
std::to_chars_result::ptr 不是字符串结尾,误用就越界
std::to_chars 返回的 ptr 指向**最后一个有效字符的下一个位置**,不是 buffer 末尾,更不是 '\0' 所在处。把它当 C 字符串指针直接传给 printf 或 std::string(const char*),大概率读到未初始化内存或崩溃。
- 取有效长度唯一安全方式:
result.ptr - buf,不是strlen(buf)(buffer 里根本没写'\0') - 要构造
std::string:用std::string(buf, result.ptr - buf),别用std::string(buf)(后者会按'\0'截断,但 buffer 里没有) - 要喂给
std::string_view:直接std::string_view(buf, result.ptr - buf),零拷贝、不加'\0' - 真要 C 字符串语义(比如传给
write()或printf("%s", ...)):仅在result.ec == std::errc{}且result.ptr 时,执行 <code>*result.ptr = '\0';别写buf[31] = '\0'——若实际只写了 5 字节,这会覆盖后面可能的有效数据
float/double 用 std::to_chars 输出不可控,别默认信任
std::to_chars 对浮点数的格式选择(f 还是 e)、是否补零、小数位数,完全由“最短可 round-trip 的十进制表示”决定。它不接受精度参数,且 libstdc++ 和 libc++ 输出可能不一致。
立即学习“C++免费学习笔记(深入)”;
- 常见错误现象:UI 显示
0.1变成"0.10000000000000001",日志金额对不齐,金融校验失败 - 想固定 2 位小数?
std::to_chars做不到。std::chars_format::fixed只控制格式,不控精度;C++17 中precision参数未被任何主流标准库实现支持 - 必须用固定格式时,切回
sprintf(buf, "%.2f", x)(注意线程安全)或fmt::format("{:.2f}", x) - 遇到
INFINITY、NaN、次正规数,std::to_chars直接返回std::errc::invalid_argument,不处理
和 sprintf / std::to_string 性能差距本质在哪
差距不是“一点点”,而是路径级差异:sprintf 每次要解析格式串、查 locale、处理宽度/精度、动态估算长度、最后还要补 '\0';std::to_chars 编译期就确定转换逻辑,全程无分支、无查表、无分配。
- 实测单次开销(x86-64):
std::to_chars约 10–30 ns,sprintf100–500 ns,std::to_string200–800 ns - 高频场景(如日志序列化百万计数器)下,真正拖慢吞吐的往往不是
to_chars本身,而是后续操作:反复分配栈 buffer、隐式构造std::string、错误地加'\0'导致越界检查开销 - 压测翻车第一原因是缓冲区太小触发大量
std::errc::value_too_large,但被忽略后仍继续跑,结果误判为“性能差”
最易被忽略的点是:它不写 '\0'、不检查 buffer 边界、不处理 inf/NaN、也不保证跨平台输出一致——这些“缺失”恰恰是它快的代价。你得自己管好缓冲区、错误分支、长度计算和后续消费方式,否则所谓高性能只是幻觉。



















