23.5K Star的C++格式化库fmt,比printf快50%,MongoDB和PyTorch都在用

C++开发者对字符串格式化这件事大概都有同感:printf系列不支持自定义类型且有安全隐患,iostreams用起来又过于繁琐。fmt的出现,一次性解决了速度、安全和易用性三个问题。这个库目前在GitHub上积累了23.5K Star,被MongoDB、PyTorch、MariaDB、Windows Terminal等众多工业级项目采用。

正文顶部截图

它能做什么

fmt的核心定位是替代C++中所有现有的格式化方案。具体功能包括:

  • 实现C++20 std::format和C++23 std::print标准接口
  • 格式字符串语法与Python的format函数一致,学习成本低
  • 浮点数格式化采用Dragonbox算法,保证正确舍入和往返精度
  • 编译期格式字符串校验,错误写法在编译阶段就会被拦截,不会留到运行时崩溃
  • 可选header-only模式,无外部依赖,只需包含头文件即可使用

性能到底怎么样

基准测试数据最能说明问题。在macOS上用clang编译的测试中,对同一个格式字符串执行200万次格式化输出:

方法 耗时(秒)
{fmt} 12.1 fmt::print 0.44
libc printf 0.66
Folly Format folly::format 1.28
libc++ std::ostream 1.63
Boost Format 1.88 boost::format 3.89

fmt比printf快约50%,比iostreams快约3.7倍。在浮点数格式化上,fmt比ostringstream和sprintf快20到30倍,甚至超过了Google的double-conversion和ryu这两个专门做浮点转换的库。

README区域截图

代码体积同样值得关注。优化编译后,fmt生成的可执行文件大小为54KB,与printf持平,而Boost Format达到530KB,是fmt的近10倍。编译时间方面,fmt耗时5.0秒,介于printf的1.6秒和Boost Format的55.0秒之间,性价比明显。

简单上手

API设计直接,输出到标准终端一行搞定:

fmt::print("Hello, {}\n", "world");

格式化字符串同样直观:

std::string s = fmt::format("The answer is {}.", 42);

支持位置参数,便于国际化场景:

std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");

此外还内置了时间日期格式化、容器输出、文件写入、终端彩色文本样式等功能。一个库覆盖了日常开发中绝大部分格式化需求。

哪些项目在用

fmt的使用者列表本身就是一份重量级C++项目清单:MongoDB用它在分布式文档数据库中做格式化输出,PyTorch在机器学习框架中集成它,MariaDB在关系型数据库里调用它。其他采用者包括Ceph分布式存储、ClickHouse分析数据库、Scylla NoSQL数据库、Windows Terminal、Blizzard战网、0 A.D.即时战略游戏、Envoy代理、Folly框架、Kodi媒体中心等。

这些项目对性能、稳定性和跨平台一致性要求苛刻,fmt通过了这些场景的检验。

迁移成本

对于已有代码库,LLVM的clang-tidy工具从v18起内置modernize-use-std-print检查项,可以自动将printf和fprintf调用转换为fmt::print。这意味着从旧式API迁移不需要逐行手动重写。

总结

fmt在C++格式化领域给出了一个干净的解:比printf快、比iostreams简洁、编译期安全检测、零外部依赖、MIT许可证。23.5K Star和广泛的工业采用提供了独立于官方宣传的第三方验证。如果你仍在维护C++项目,从printf或iostreams迁移到fmt,收益数据清晰,试错成本低。

采用提供了独立于官方宣传的第三方验证。如果你仍在维护C++项目,从printf或iostreams迁移到fmt,收益数据清晰,试错成本低。

更多推荐