拓冰建站拓冰建站
首页 / 资讯中心 / 正文

{fmt} 12.x 现代 C++ 格式化库完全指南:核心 API、编译期安全与性能实战

{fmt} 12.x 现代 C 格式化库完全指南核心 API、编译期安全与性能实战【免费下载链接】fmtA modern formatting library项目地址: https://gitcode.com/GitHub_Trending/fm/fmt{fmt} 是一个开源的现代 C 格式化库为 C 的 stdio 和 C 的 iostreams 提供更快、更安全的替代方案并实现了 C20std::format与 C23std::print标准语义。本文以本仓库fm/fmt的 README.md 为骨架结合 include/fmt 源码与 test 测试用例系统讲解 {fmt} 的安装集成、核心格式化 API、格式语法、编译期错误检查、性能特性与源码结构帮助你在实际项目中安全、高效地使用它替换sprintf与 iostreams。一、{fmt} 是什么{fmt} 是一个开源的格式化库定位是 C stdio 与 C iostreams 的快速且安全的替代方案。它的版本号定义在 include/fmt/base.h 中#define FMT_VERSION 120201即当前仓库对应12.2.1版本主版本major * 10000 minor * 100 patch与 README 性能表中出现的 fmt 12.2 一致。与传统的printf族函数和 iostreams 相比{fmt} 的核心设计目标可以概括为安全性完全类型安全格式字符串错误可在编译期报告自动内存管理防止缓冲区溢出高性能比常见标准库实现的(s)printf、iostreams、to_string、to_chars更快易用性代码库自包含、体积小、无外部依赖采用宽松的 MIT 许可见 LICENSE可移植性跨平台输出一致支持较老的编译器且在-Wall -Wextra -pedantic等高警告级别下保持无警告。二、核心特性一览README 完整列出的特性包括特性说明简单格式化 API支持位置参数positional arguments便于本地化标准兼容实现 C20std::format与 C23std::printPython 风格语法格式字符串语法与 Python 的str.format相似快速 IEEE 754 浮点格式化基于 Dragonbox 算法保证正确舍入、最短表示与往返round-trip保证可移植 Unicode 支持跨平台一致地处理 Unicode 文本安全的 printf 实现包含 POSIX 位置参数扩展可扩展性支持用户自定义类型格式化高编译期检查能力格式字符串错误可在编译期报告小体积最小配置只需base.h、format.h、format-inl.h三个文件头文件可选模式通过FMT_HEADER_ONLY宏启用纯头文件配置默认与区域设置无关不依赖 locale输出稳定可预测其中最小配置只需三个文件的说法在仓库中可以得到印证include/fmt 目录下的 base.h、format.h、format-inl.h 构成了库的核心实现其余头文件如chrono.h、ranges.h、os.h、color.h都是围绕核心的扩展模块。2.1 头文件模式与宏开关在 include/fmt/base.h 中可以看到大量条件编译宏其中与用户配置直接相关的重要宏包括FMT_HEADER_ONLY启用纯头文件模式无需链接编译好的库见 include/fmt/base.hFMT_UNICODE控制 Unicode 支持对应 CMake 选项FMT_UNICODE默认 ONFMT_CONSTEVAL/FMT_USE_CONSTEVAL控制 C20consteval编译期检查能力见 include/fmt/base.hFMT_ENFORCE_COMPILE_STRING强制格式字符串必须使用FMT_STRING包装见 include/fmt/base.h。这些宏的默认值会根据编译器版本GCC、Clang、MSVC和 C 标准版本自动推断用户也可以在编译时手动覆盖。三、构建与集成方式{fmt} 使用 CMake 构建主配置文件为根目录的 CMakeLists.txt。构建时支持多种集成路径。3.1 作为独立项目构建git clone 项目地址 cd fmt mkdir build cd build cmake .. cmake --build . --target fmt构建产物默认输出到build/bin目录见 CMakeLists.txt。若未指定CMAKE_BUILD_TYPECMake 会自动设为Release见 CMakeLists.txt。3.2 通过 add_subdirectory 集成CMakeLists.txt 会判断 fmt 是作为主项目还是子项目构建因此可以直接作为子目录嵌入add_subdirectory(fmt) target_link_libraries(my_app PRIVATE fmt::fmt)仓库的 test/add-subdirectory-test 就是一个完整的子目录集成示例。3.3 通过 find_package 集成find_package(fmt REQUIRED) target_link_libraries(my_app PRIVATE fmt::fmt)安装后的 CMake 配置模板位于 support/cmake/fmt-config.cmake.in。test/find-package-test 提供了可参考的用法。3.4 头文件模式Header-only如果希望避免链接编译产物只需定义宏FMT_HEADER_ONLY然后直接包含头文件即可。README 也指出这是可选配置适合快速试验或对二进制体积不敏感的场景。3.5 常用 CMake 选项CMakeLists.txt 中定义的选项包括选项默认值说明FMT_DOC主项目时 ON生成文档目标FMT_INSTALL主项目时 ON生成 install 目标FMT_TEST主项目时 ON生成测试目标FMT_FUZZOFF生成模糊测试目标FMT_CUDA_TESTOFF生成 CUDA 测试目标FMT_OSON包含操作系统相关 API如os.hFMT_MODULE视编译器而定构建 C20 模块库FMT_UNICODEON启用 Unicode 支持FMT_PEDANTICOFF启用额外警告与耗时测试FMT_WERROROFF将编译警告视为错误四、核心 API 实战从 Hello World 到容器输出README 的 Examples 章节提供了从入门到进阶的完整示例下面逐一展开并结合源码补充细节。4.1 打印到标准输出#include fmt/base.h int main() { fmt::print(Hello, world!\n); }从 C20 起fmt::print与标准库的std::print语义一致。仅需包含轻量的 include/fmt/base.h 即可使用fmt::print与fmt::format等最核心的 API。4.2 格式化字符串std::string s fmt::format(The answer is {}., 42); // s The answer is 42.fmt::format返回std::string{}是替换字段replacement field按参数顺序替换。这是最基本的用法。4.3 位置参数Positional Argumentsstd::string s fmt::format(Id rather be {1} than {0}., right, happy); // s Id rather be happy than right.花括号内的数字索引用于引用参数位置。README 指出位置参数的设计初衷是便于本地化翻译人员调整词序时无需改动代码参数顺序只需重排格式串中的索引。这也呼应了 README Features 中简单格式化 API with positional arguments for localization的描述。4.4 日期与时间格式化#include fmt/chrono.h int main() { auto now std::chrono::system_clock::now(); fmt::print(Date and time: {}\n, now); fmt::print(Time: {:%H:%M}\n, now); }输出示例README 原文Date and time: 2023-12-26 19:10:31.557195597 Time: 19:10fmt::chrono.h为std::chrono时间点和时长提供格式化支持{:%H:%M}中的%H、%M是 strftime 风格的时间说明符。这一点在 test/chrono-test.cc 中得到充分验证例如EXPECT_EQ(fmt::format({:12%H:%M:%S}, std::chrono::seconds(12345)), ...); EXPECT_EQ(fmt::format({:~^12%H:%M:%S}, std::chrono::seconds(12345)), ...);测试还验证了{:%H:%M:%S}与{:%T}等价见 test/chrono-test.cc以及时长的小数精度控制{:.3%H:%M:%S}见 test/chrono-test.cc。4.5 容器输出#include vector #include fmt/ranges.h int main() { std::vectorint v {1, 2, 3}; fmt::print({}\n, v); }输出[1, 2, 3]include/fmt/ranges.h 定义了range_format枚举见 include/fmt/ranges.h可区分序列、映射、集合、字符串等容器形态实现定制化的容器打印。该头文件还提供fmt::join可用指定分隔符拼接元素fmt::print({}, fmt::join(v, , )); // 1, 2, 3 fmt::print({:02}, fmt::join(v, , )); // 01, 02, 03应用元素级格式相关实现位于 include/fmt/ranges.h。4.6 单线程写文件#include fmt/os.h int main() { auto out fmt::output_file(guide.txt); out.print(Dont {}, Panic); }fmt::output_file创建并返回一个ostream对象见 include/fmt/os.h。os.h中还包含buffered_file类见 include/fmt/os.h底层封装了FILE*并自动处理资源管理。ostream::print内部会根据参数是否可加锁选择vprint_buffered或vprint见 include/fmt/os.h。4.7 彩色与文本样式输出#include fmt/color.h int main() { fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, Hello, {}!\n, world); 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 支持。源码层面fmt::color是包含 256 色及扩展色的枚举见 include/fmt/color.hfmt::emphasis是粗体、斜体、下划线等样式枚举见 include/fmt/color.hfg()/bg()分别构造前景色、背景色样式operator|用于组合样式见 include/fmt/color.h。五、格式字符串语法精要{fmt} 的格式语法与 Python 的str.format相似本仓库的 doc/syntax.md 对其有完整定义。核心文法见 doc/syntax.mdformat_spec :: [[fill]align][sign][#][0][width][. precision][L][type] fill :: a character other than { or } precision :: integer | { [arg_id] }各组件要点填充与对齐fill/align左对齐、右对齐、^居中对齐填充字符必须是除{、}之外的任意 Unicode 码点且只有在指定对齐方式时填充字符才生效。例如fmt::format([{:*^10}], 42)结果为[****42****]见 doc/syntax.md符号sign强制显示正负号、-仅负数显示负号、空格表示正数前留空格备用形式#如十六进制输出0x前缀零填充0数字前补零宽度与精度宽度和精度既可以是字面整数也可以写成{arg_id}从参数动态取值见 doc/syntax.mdL使用与区域设置相关的输出类型type如d十进制整数、f定点浮点、e科学计数法等。动态宽度的写法示例源自 test/chrono-test.ccfmt::format({:{}%H:%M:%S}, std::chrono::seconds(12345), 12)其中第二个参数12作为宽度传入。六、编译期格式检查把错误消灭在编译阶段{fmt} 最突出的安全特性之一是格式字符串可以在编译期被检查。README 给出了这一示例std::string s fmt::format({:d}, I am not a number);在 C20 下这会直接产生编译期错误因为d对字符串类型而言是无效的格式说明符——错误在编译阶段就被拦截而不是等到运行时打印出错误内容或发生未定义行为。从源码看这一能力依赖 C20 的consteval见 include/fmt/base.h 对FMT_CONSTEVAL的处理以及fstring的consteval构造见 include/fmt/base.h。在更早的 C 标准下可以通过FMT_STRING宏包装字符串字面量获得同样的检查能力#include fmt/format.h std::string s fmt::format(FMT_STRING({:d}), I am not a number); // 编译期错误test/format-test.cc 中的测试证实了FMT_STRING的用法例如EXPECT_EQ(fmt::format(FMT_STRING({}), 42), 42); EXPECT_EQ(fmt::format(FMT_STRING({foo}{bar}), bar_a bar, foo_a foo), foobar);6.1 编译期字符串编译Compile-time Formattinginclude/fmt/compile.h 提供了FMT_COMPILE宏可在编译期把格式字符串编译为高效的格式化代码从而进一步提升运行时性能std::string s fmt::format(FMT_COMPILE({}), 42);其定义见 include/fmt/compile.h在支持FMT_COMPILE_H_的完整环境下展开为FMT_STRING_IMPL(s, fmt::compiled_string)否则退化为FMT_STRING(s)保证兼容性。README 也提到{fmt} 可以可选地把格式字符串编译为高效的格式化代码。七、性能更快、更省、更小的代码体积7.1 总体性能表现README 明确指出{fmt} 比sprintf和 iostreams 快百分之几十到 20–30 倍在数值格式化场景尤为明显同时最小化动态内存分配。这主要得益于基于Dragonbox 算法的 IEEE 754 浮点格式化保证正确舍入、最短表示与往返保证可选编译期字符串编译消除运行时格式解析开销。本仓库 doc/perf.svg 记录了 double to string 的对比基准在该图中 fmt 的耗时显著低于ostringstream、ostrstream、sprintf、doubleconv横轴为时间 ns越小越好直观印证了 README 关于浮点格式化性能的描述。需要说明的是该图表来自仓库文档具体硬件环境与基准方法学请参考 README 中提到的 format-benchmark 与 dtoa-benchmark 基准项目。7.2 编译时间与代码膨胀README 引用了 bloat-test 脚本的方法学生成 100 个翻译单元每个单元使用对应格式化方法 5 次模拟中等规模项目排除库和模块自身的构建开销取三次运行最佳值。结果如下README 原文数据优化构建-O3方法编译时间s二进制大小KiB剥离后大小KiBprintf1.65450IOStreams25.59884fmt 12.2 (headers)5.15450fmt 12.2 (module)3.75950Boost Format 1.9249.1517317非优化构建方法编译时间s二进制大小KiB剥离后大小KiBprintf1.65450IOStreams26.08868fmt 12.2 (headers)4.98784fmt 12.2 (module)3.27768Boost Format 1.9235.7741431关键结论均来自 README 原文优化构建下{fmt} 头文件模式与printf的剥离后二进制大小相同50 KiB但编译时间与 IOStreams、Boost.Format 相比大幅缩短使用模块化 {fmt}C20 module可将优化构建的编译时间再降低 27%且剥离后二进制大小不变libc、libc、libfmt、libfmt-module以共享库方式链接仅比较格式化函数本身的开销Boost.Format 为纯头文件实现。关于 C20 模块构建CMakeLists.txt 显示了模块支持的前置条件CMake ≥ 3.28、Ninja ≥ 1.11 或 VS 17.4、GCC ≥ 14CXX_MODULE 扫描要求更高、Clang ≥ 16 或 MSVC 17.4。八、扩展格式化用户自定义类型{fmt} 的可扩展性README Features 之一允许为自定义类型实现fmt::formatter特化从而无缝接入fmt::format/fmt::print。test/format-test.cc 展示了这一模式template struct fmt::formatterAnswer { // parse() 解析格式说明符 // format() 生成输出 }; EXPECT_EQ(fmt::format(FMT_STRING({}), Answer()), 42); EXPECT_EQ(fmt::format(FMT_STRING({}), answer), 42);自定义类型的格式化需要实现parse与format两个成员前者解析格式说明符可选最小实现可直接接受空说明符后者把对象写入输出迭代器。详细的 API 约定见 doc/api.md。九、源码结构导读本仓库的核心代码布局如下便于按需查阅路径职责include/fmt/base.h核心基础 APIfmt::format、fmt::print、fmt::format_to、类型检测与宏定义include/fmt/format.h核心格式化实现大整数、浮点、编译期解析等include/fmt/format-inl.h非内联实现细节错误信息、文件写入等include/fmt/chrono.hstd::chrono时间点与时长格式化include/fmt/ranges.h容器 / 范围 / 元组格式化fmt::joininclude/fmt/os.h文件输出output_file、buffered_fileinclude/fmt/color.hANSI 颜色与文本样式include/fmt/compile.h编译期字符串编译FMT_COMPILEinclude/fmt/printf.h安全的printf兼容实现include/fmt/ostream.h与std::ostream互操作src编译型模式的实现源文件format.cc、os.cc、fmt.cc、fmt-c.cctest覆盖各模块的单元测试gtest与模糊测试目标doc文档API 参考api.md、语法syntax.md、快速上手get-started.mdREADME 提到最小配置由base.h、format.h和format-inl.h三个文件组成正是 include/fmt 目录中的三个核心文件——这对应了 Feature 中Small code size both in terms of source code的设计便于将核心代码直接嵌入到项目源码树中。十、可靠性与安全性保障README 强调 {fmt} 的可靠性来自两方面广泛的测试集本仓库 test 目录包含 30 余个测试文件覆盖base-test.cc、format-test.cc、chrono-test.cc、printf-test.cc、ranges-test.cc、color-test.cc、os-test.cc、xchar-test.cc、unicode-test.cc等此外还有header-only-test.cc验证头文件模式与module-test.cc验证 C20 模块模式等专项测试持续模糊测试fuzzing仓库 test/fuzzing 目录包含针对浮点float.cc、chronochrono-duration.cc、chrono-timepoint.cc、命名参数named-arg.cc等场景的 fuzz 目标可结合FMT_FUZZCMake 选项构建。安全性方面格式化全程类型安全、错误可在编译期报告、自动内存管理防止缓冲区溢出且代码在-Wall -Wextra -pedantic级别下保持无警告对应 CMake 中的FMT_PEDANTIC、FMT_WERROR选项。十一、典型使用场景与生态README 列举了若干知名使用方以下名称均来自 README 原文供参考Apples FoundationDB、Blizzard Battle.net、Ceph、ClickHouse、Envoy、Folly、MariaDB、MongoDB、PyTorch、Quill、Seastar、spdlog、Windows Terminal。这些项目横跨数据库、分布式系统、日志库、终端等场景从侧面印证了 {fmt} 在需要高性能、高安全格式化的 C 项目中的普适性。从使用模式上归纳{fmt} 最常见的落地场景包括日志系统如 spdlog 内部大量使用 {fmt} 进行格式化高性能数值输出利用 Dragonbox 浮点算法与编译期字符串编译替代sprintf/to_chars本地化友好的 UI 文本利用位置参数调整语序而无需改动代码终端工具利用color.h输出彩色、带样式的文本安全审计敏感的代码路径利用编译期格式检查杜绝格式串漏洞与缓冲区溢出。十二、快速参考本文要点回顾选型需要比printf/iostreams 更快、更安全且语法现代的 C 格式化能力时{fmt} 是直接的选择且其 API 与 C20/23 标准对齐集成支持add_subdirectory、find_package、纯头文件FMT_HEADER_ONLY三种方式CMake 选项集中在根目录 CMakeLists.txt核心 APIfmt::print、fmt::format、位置参数、chrono.h时间格式化、ranges.h容器输出、os.h文件输出、color.h彩色输出安全C20 下格式串错误自动变为编译期错误C17 及更早可用FMT_STRING、FMT_COMPILE显式开启编译期检查性能数值格式化场景收益最大模块化构建可进一步降低编译时间具体数据见 README 性能表与 doc/perf.svg深入阅读完整语法见 doc/syntax.mdAPI 细节见 doc/api.md快速上手见 doc/get-started.md更新历史见 ChangeLog.md。【免费下载链接】fmtA modern formatting library项目地址: https://gitcode.com/GitHub_Trending/fm/fmt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门