{fmt}是一个开源格式化库,为 C stdio 和 C++ iostream 提供快速、安全的替代方案。
如果您喜欢这个项目,请考虑向帮助乌克兰战争受害者的基金之一捐款:https://www.stopputin.net/。
文档
备忘单
问答:使用标签 fmt 在 StackOverflow 上提问。
在编译器资源管理器中尝试 {fmt}。
带有用于本地化的位置参数的简单格式 API
C++20 std::format 和 C++23 std::print 的实现
格式化字符串语法类似于Python的格式
快速 IEEE 754 浮点格式化程序,使用 Dragonbox 算法提供正确的舍入、缩短和往返保证
便携式 Unicode 支持
安全 printf 实现,包括位置参数的 POSIX 扩展
可扩展性:支持用户定义类型
高性能:比(s)printf
、 iostreams 、 to_string
和to_chars
的常见标准库实现更快,请参阅速度测试和每秒将一亿个整数转换为字符串
代码量小,源代码最小配置仅包含三个文件: core.h
、 format.h
和format-inl.h
,以及编译后的代码;请参阅编译时间和代码膨胀
可靠性:该库进行了广泛的测试,并且不断进行模糊测试
安全性:该库是完全类型安全的,可以在编译时报告格式字符串中的错误,自动内存管理可防止缓冲区溢出错误
易于使用:小型独立代码库,无外部依赖项,宽松的 MIT 许可证
具有跨平台一致输出的可移植性以及对旧版编译器的支持
即使在高警告级别(例如-Wall -Wextra -pedantic
下,也干净且无警告的代码库
默认情况下与语言环境无关
使用FMT_HEADER_ONLY
宏启用可选的仅标头配置
请参阅文档了解更多详细信息。
打印到标准输出(运行)
#include <fmt/core.h>int main() { fmt::print("你好,世界!n"); }
格式化字符串(运行)
std::string s = fmt::format("答案是 {}.", 42);// s == "答案是 42。"
使用位置参数格式化字符串(运行)
std::string s = fmt::format("我宁愿成为 {1} 而不是 {0}。", "right", "happy");// s == "我宁愿成为快乐而不是 right ”。
打印日期和时间(运行)
#include <fmt/chrono.h>int main() { auto now = std::chrono::system_clock::now(); fmt::print("日期和时间:{}n",现在); fmt::print("时间: {:%H:%M}n", 现在); }
输出:
Date and time: 2023-12-26 19:10:31.557195597 Time: 19:10
打印容器(运行)
#include <向量>#include <fmt/ranges.h>int main() { std::vector<int> v = {1, 2, 3}; fmt::print("{}n", v); }
输出:
[1, 2, 3]
在编译时检查格式字符串
std::string s = fmt::format("{:d}", "我不是数字");
这会在 C++20 中产生编译时错误,因为d
是字符串的无效格式说明符。
从单线程写入文件
#include <fmt/os.h>int main() { auto out = fmt::output_file("guide.txt"); out.print("不要{}", "恐慌"); }
这比 fprintf 快 5 到 9 倍。
使用颜色和文本样式进行打印
#include <fmt/color.h>int main() { fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "你好,{}!n", "世界" ); fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | fmt::emphasis::underline, "Olá, {}!n", "Mundo"); fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, "你好{}!n", "世界"); }
在支持 Unicode 的现代终端上输出:
图书馆 | 方法 | 运行时间,秒 |
---|---|---|
库 | 打印函数 | 0.91 |
库++ | std::ostream | 2.49 |
{fmt} 9.1 | fmt::打印 | 0.74 |
升压格式 1.80 | 增强::格式 | 6.26 |
愚蠢的格式 | 愚蠢::格式 | 1.87 |
{fmt} 是最快的基准测试方法,比printf
快约 20%。
上述结果是通过使用clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT
在 macOS 12.6.1 上构建tinyformat_test.cpp
并取三轮运行中的最佳结果生成的。在测试中,格式字符串"%0.10f:%04d:%+g:%s:%p:%c:%%n"
或等效内容被填充 2,000,000 次,并将输出发送到/dev/null
;有关更多详细信息,请参阅来源。
在 IEEE754 float
和double
格式(dtoa-基准)上,{fmt} 比std::ostringstream
和sprintf
快 20-30 倍,并且比双精度转换和 ryu 更快:
format-benchmark 中的脚本 bloat-test.py 测试重要项目的编译时间和代码膨胀。它生成 100 个翻译单元,并在每个单元中使用printf()
或其替代方法五次,以模拟一个中型项目。下表显示了生成的可执行文件大小和编译时间(Apple clang 版本 15.0.0 (clang-1500.1.0.2.5)、macOS Sonoma,三者最佳)。
优化构建(-O3)
方法 | 编译时间,秒 | 可执行文件大小,KiB | 剥离尺寸,KiB |
---|---|---|---|
打印函数 | 1.6 | 54 | 50 |
IO流 | 25.9 | 98 | 84 |
FMMT 83652df | 4.8 | 54 | 50 |
小格式 | 29.1 | 161 | 136 |
升压格式 | 55.0 | 第530章 | 第317章 |
{fmt} 编译速度很快,并且在每次调用的二进制大小方面与printf
相当(在该系统的舍入误差范围内)。
非优化构建
方法 | 编译时间,秒 | 可执行文件大小,KiB | 剥离尺寸,KiB |
---|---|---|---|
打印函数 | 1.4 | 54 | 50 |
IO流 | 23.4 | 92 | 68 |
{fmt} 83652df | 4.4 | 89 | 85 |
小格式 | 24.5 | 204 | 161 |
升压格式 | 36.4 | 第831章 | 第462章 |
libc
、 lib(std)c++
和libfmt
都作为共享库链接,仅用于比较格式化函数开销。 Boost Format 是一个仅包含标头的库,因此它不提供任何链接选项。
请参阅构建库以获取有关如何构建库和运行单元测试的说明。
基准驻留在单独的存储库 format-benchmarks 中,因此要运行基准,您首先需要克隆此存储库并使用 CMake 生成 Makefile:
$ git clone --recursive https://github.com/fmtlib/format-benchmark.git $ cd format-benchmark $ cmake .
然后你可以运行速度测试:
$ make speed-test
或膨胀测试:
$ make bloat-test
clang-tidy v18 提供了 Modernize-use-std-print 检查,如果配置为这样做,则能够将printf
和fprintf
的出现转换为fmt::print
。 (默认情况下它转换为std::print
。)
0 AD:一款免费、开源、跨平台的即时战略游戏
AMPL/MP:数学规划的开源库
Apple 的 FoundationDB:开源、分布式、事务性键值存储
Aseprite:动画精灵编辑器和像素艺术工具
AvioBook:全面的飞机操作套件
Blizzard Battle.net:在线游戏平台
Celestia:空间的实时 3D 可视化
Ceph:可扩展的分布式存储系统
ccache:编译器缓存
ClickHouse:分析数据库管理系统
ContextVision:医学成像软件
Contour:现代终端模拟器
CUAUV:康奈尔大学的自主水下航行器
Drake:非线性动力系统的规划、控制和分析工具箱 (MIT)
Envoy:C++ L7 代理和通信总线 (Lyft)
FiveM:GTA V 的修改框架
fmtlog:一个高性能的 fmtlib 风格的日志库,延迟为纳秒级
Folly:Facebook 开源库
GemRB:Bioware Infinity Engine 的便携式开源实现
Grand Mountain Adventure:一款精美的开放世界滑雪和单板滑雪游戏
HarpyWar/pvpgn:经过调整的玩家对玩家游戏网络
KBEngine:开源 MMOG 服务器引擎
Keypirinha:Windows 语义启动器
Kodi(以前的 xbmc):家庭影院软件
Knuth:高性能比特币全节点
libunicode:现代 C++17 Unicode 库
MariaDB:关系数据库管理系统
Microsoft Verona:研究并发所有权的编程语言
MongoDB:分布式文档数据库
MongoDB Smasher:生成随机数据集的小工具
OpenSpace:开源天文可视化框架
PenUltima Online (POL):MMO 服务器,与大多数 Ultima Online 客户端兼容
PyTorch:一个开源机器学习库
quasardb:分布式、高性能、关联数据库
Quill:异步低延迟日志库
QKW:通用化别名以简化导航并执行复杂的多行终端命令序列
redis-cerberus:Redis 集群代理
redpanda:速度提高 10 倍的 Kafka® 替代品,用于用 C++ 编写的关键任务系统
rpclib:现代 C++ msgpack-RPC 服务器和客户端库
Salesforce Analytics Cloud:商业智能软件
Scylla:与 Cassandra 兼容的 NoSQL 数据存储,可在单个服务器上每秒处理 100 万个事务
Seastar:先进的开源 C++ 框架,适用于现代硬件上的高性能服务器应用程序
spdlog:超快速 C++ 日志库
Stellar:金融平台
触摸手术:手术模拟器
TrinityCore:开源 MMORPG 框架
? userver框架:开源异步框架,具有丰富的抽象和数据库驱动程序
Windows 终端:新的 Windows 终端
更多的...
如果您知道使用此库的其他项目,请通过电子邮件或提交问题让我知道。
那么为什么还要另一个格式化库呢?
有很多方法可以完成此任务,从 printf 系列函数和 iostream 等标准方法到 Boost Format 和 FastFormat 库。创建新库的原因是我发现的每个现有解决方案要么存在严重问题,要么没有提供我需要的所有功能。
printf
的好处是它非常快并且作为 C 标准库的一部分很容易使用。主要缺点是它不支持用户定义的类型。 printf
也存在安全问题,尽管在 GCC 中使用 __attribute__ ((format (printf, ...)) 可以在一定程度上缓解这些问题。有一个 POSIX 扩展将 i18n 所需的位置参数添加到printf
但它不是 C99 的一部分,可能在某些平台上不可用。
iostreams 的主要问题最好用一个例子来说明:
std::cout << std::set precision(2) << std::fixed << 1.23456 << "n";
与 printf 相比,需要输入大量内容:
printf("%.2fn", 1.23456);
FastFormat 的作者 Matthew Wilson 将其称为“V 形地狱”。 iostreams 在设计上不支持位置参数。
好的部分是 iostream 支持用户定义的类型并且是安全的,尽管错误处理很尴尬。
这是一个非常强大的库,支持类似printf
的格式字符串和位置参数。它的主要缺点是性能。根据各种基准测试,它比此处考虑的其他方法慢得多。 Boost Format 还存在过多的构建时间和严重的代码膨胀问题(请参阅基准)。
这是一个有趣的库,它快速、安全并且具有位置参数。然而,它有很大的局限性,引用其作者的话:
当前设计中无法容纳的三个功能是:
前导零(或任何其他非空格填充)
八进制/十六进制编码
运行时宽度/对齐规范
它也相当大,并且严重依赖于 STLSoft,这对于某些项目的使用可能过于严格。
这不是一个格式化库,但为了完整性我决定将其包含在这里。作为 iostream,它面临着逐字文本与参数混合的问题。该库相当快,但在整数格式化方面比fmt::format_to
慢,并且在 Karma 自己的基准上进行格式字符串编译,请参阅每秒将一亿个整数转换为字符串。
{fmt} 是根据 MIT 许可证分发的。
文档中的格式字符串语法部分基于 Python 字符串模块文档中的一节。因此,该文档根据 doc/python-license.txt 中提供的 Python Software Foundation 许可证分发。它仅适用于您分发 {fmt} 文档的情况。
{fmt} 库由 Victor Zverovich (vitaut) 维护,并得到了许多其他人的贡献。请参阅贡献者和版本以了解其中一些名称。如果您的贡献未列出或提及不正确,请告诉我们,我们将予以纠正。
要报告安全问题,请在安全公告中披露。
该项目由一组志愿者在合理努力的基础上维护。因此,在公开曝光之前,请给我们至少90天的时间进行修复。