📌 项目地址:fmtlib/fmt | ⭐ 24,060 颗星 | 🔧 C++ | 📜 未标注
先说一个少见的事实
C++20 的 std::format 和 C++23 的 std::print,标准提案的起点就是这个第三方库。通常的顺序是标准先定、各家库再实现,{fmt} 把顺序反了过来:先做出好用的东西,再被吸进标准。
所以这篇文章的问题不是“这个库值不值得用”,而是“为什么标准委员会选中了它”。
printf 和 iostreams 各自烂在哪
printf 类型不安全,%d 对上 double 就是未定义行为,格式串写错编译器未必报错,运行时才炸。iostreams 类型安全,但慢、冗长,格式控制一大串 setw/setfill/setprecision 套着用,可读性差。
{fmt} README 里给自己的定位是“快速且安全的 C stdio 和 C++ iostreams 替代品”。它的做法:
- 格式串语法类似 Python 的
str.format,{}占位,支持{0}、{1}位置参数(本地化必需,不同语言语序不同) - 格式串错误可以在编译期报出来,而不是运行时
- 全类型安全,自动内存管理,没有缓冲区溢出问题
- 性能上比常见标准库实现的
(s)printf、iostreams、to_string、to_chars都快
浮点数格式化是硬功夫
我觉得这是这个库技术含量最高的部分。它用 Dragonbox 算法做 IEEE 754 浮点格式化,同时保证三件事:正确舍入、最短表示、round-trip(格式化再解析回来还是原值)。
这三个保证同时满足并不容易。很多标准库的 to_chars 在这些指标上要么做不到最短,要么慢。作者写过一篇 “Converting a hundred million integers to a second“(README 中链接),整数转字符串能做到每秒上亿次的量级,有兴趣可以看实现细节。
它真的很小
最小配置只要三个文件:base.h、format.h、format-inl.h。没有外部依赖。塞进任何项目都没有负担——这在 C++ 库里不算常见,很多“header-only”库实际上牵扯一堆配置宏和平台分支。
README 还有专门的 Compile time and code bloat 对比章节,编译时间和产物体积都是它的卖点,不只是运行速度。
和 std::format 怎么选
既然 {fmt} 就是 std::format 的原型,能不能直接用标准库?我的判断:
- 编译器不支持 C++20/23:没得选,{fmt} 是唯一路径。MSVC 之外,很多工具链的
std::format/std::print落地进度参差。 - 支持了:标准库够用就用标准库。但 {fmt} 功能通常跑在标准前面(比如
std::print很多标准库还没实现),且跨平台行为一致。
另外它附带一个安全的 printf 实现,含 POSIX 位置参数扩展——存量代码从 printf 迁移时有现成的过渡路径。
可靠性背书
- 24060 个 star,作者 Victor Zverovich 长期活跃维护
- 持续 fuzz 测试(OSS-Fuzz 项目)
- 大规模测试集,Linux/macOS/Windows 三平台 CI
- MIT 许可证,商用无负担
上手成本几乎为零
格式串语法照搬 Python str.format 的思路,写过 Python 的人不用学。README 给了两条快速路径:fmt.dev 官方文档,以及 Compiler Explorer 在线示例——浏览器里直接跑,一行代码不用装。还有第三方 Cheat Sheet。
问题可以去 StackOverflow 的 fmt 标签下问,作者本人在那边答疑。
一句话总结
如果你的 C++ 项目还在用 printf 或 << 拼字符串,换 {fmt} 是一次收益明确、风险极低的改动——尤其是它只有三个文件的时候。