{fmt} 12.x 更新日志全解析:从 C11 格式化 API 到编译期格式化的演进路线 发布时间:2026/9/11 14:33:09 尧图网站设计 {fmt} 12.x 更新日志全解析从 C11 格式化 API 到编译期格式化的演进路线【免费下载链接】fmtA modern formatting library项目地址: https://gitcode.com/GitHub_Trending/fm/fmt本指南以仓库根目录的 ChangeLog.md 为骨架完整梳理 {fmt}A modern formatting library12.x 及历史版本的核心变更并结合 include/fmt 头文件、src/fmt-c.cc 实现与 CMakeLists.txt 构建配置逐条解读新 API 的用法、性能优化的依据与迁移要点。读完本文你将掌握 fmt-c C 接口、C20 模块、编译期格式化FMT_COMPILE / FMT_STATIC_FORMAT、浮点格式化性能优化等关键能力的真实用法以及从 8.0 升级到 12.2 时需要关注的破坏性变更。版本脉络12.2.1 与 12.2.0 的新特性速览ChangeLog 顶部记录了最新的两个版本12.2.1TBD尚未发布与12.2.02026-06-16。当前仓库源码对应的正是这两个版本的状态。12.2.0C11 格式化 APIfmt-c正式落地12.2.0 最重磅的变更是新增了面向 C 语言的快速、类型安全格式化接口。全新的fmt-c库与 include/fmt/fmt-c.h 头文件借助 C11 的_Generic关键字按参数类型进行分发性能优于printf/sprintf。ChangeLog 中给出的最小示例#include fmt/fmt-c.h fmt_print(stdout, The answer is {}.\n, 42);从 include/fmt/fmt-c.h 源码可以看到其底层设计参数类型枚举fmt_type定义了fmt_int、fmt_uint、fmt_bool、fmt_char、fmt_float、fmt_double、fmt_long_double、fmt_cstring、fmt_pointer等类型标签参数包装结构fmt_arg通过type字段与union value承载不同类型的具体数值指针则复用uint_value或pointer成员_Generic分派宏FMT_MAKE_ARG把int/long/short/char等 C 内置类型自动映射到对应的fmt_from_*构造函数并把不支持的参数类型派发到fmt_unsupported_type报错变参包装宏FMT_FORMAT_ARGS/FMT_MAKE_ARGLIST利用FMT_NARG与FMT_MAP系列宏统计参数个数上限 16 个把实参展开为fmt_arg[]数组最终调用底层入口fmt_vformat或fmt_vprint。两个 C 入口函数的实现位于 src/fmt-c.ccfmt_vformat(char* buffer, size_t size, const char* fmt, const fmt_arg* args, size_t num_args)内部把fmt_arg数组逐一转换为fmt::basic_format_argfmt::format_context再委托给fmt::vformat_to_n写入用户缓冲区返回写入的字符数参数个数超过 16 或出现未知类型时返回fmt_error_invalid_arg-2格式化过程抛出异常时返回fmt_error-1fmt_vprint(FILE* stream, ...)把参数转换后委托给fmt::vprint直接向FILE*流输出。需要特别注意的是ChangeLog 指出 fmt-c 依赖MSVC 2019 且必须开启/Zc:preprocessor标志见 include/fmt/fmt-c.h 中的#error检查原因是该接口依赖符合标准的预处理器来展开_Generic与可变参数宏。此外 12.2.0 还包含以下值得关注的点新增独立的fmt::fmt-moduleCMake 目标用于 C20 模块构建并配套了 CI 工作流默认启用完整的 Dragonbox 查找表缓存除非以二进制体积为优化目标即定义了__OPTIMIZE_SIZE__浮点格式化获得约 10%–25% 的加速std::unexpected支持格式化fmt::println新增接受fmt::text_style的重载fmt::printf支持把位置参数用作宽度与精度说明符将fmt::detail::named_arg提升为公开 APIfmt::named_argstd::byte的 formatter 从fmt/format.h迁移到fmt/std.hfmt/core.h默认与fmt/base.h等价依赖旧行为core.h 间接引入 format.h的代码必须显式包含fmt/format.h或定义FMT_DEPRECATED_HEAVY_CORE移除了fmt::say弃用了std::initializer_list版本的fmt::join与数组版本的fmt::vformat_to修复合入嵌套异常std::throw_with_nested的展开pipe 写端关闭时的挂起/断言以及c演示类型对越界整数的格式化问题。12.2.1TBD面向异常与模块的小幅增强仍在开发中的 12.2.1 集中了以下改进为std::exception_ptr新增 formatter格式化其引用的异常对象为空时输出nonestd::exceptionformatter 支持展开std::throw_with_nested创建的嵌套异常各层之间以: 连接从 C20 模块导出fmt::basic_ostream_formatter、fmt::ostream_formatter与fmt::streamed文档补充了用 CMake 使用 C20 模块含fmt::fmt-module目标与编译器要求的说明128 位整数格式化优化通过把值拆成 64 位分块而不是反复做 128 位除法全范围取值时获得约 5 倍加速修复了 chrono 格式化中超出范围的浮点时长、管道读端关闭导致的挂起、以及FMT_COMPILE与format_as用户自定义类型组合时的编译失败等问题CMake 构建树导出集不再受FMT_INSTALL影响通过add_subdirectory或FetchContent引入 {fmt} 的项目也能导出依赖fmt::*的目标fmt-c库开始像主库一样尊重BUILD_SHARED_LIBS。12.x 性能优化数字背后的实现依据ChangeLog 中多处给出了可复现的基准数据这些优化点大多能在源码中找到对应证据。浮点格式化Dragonbox 与完整缓存12.0.0 优化了默认浮点格式化用格式字符串编译format string compilation写入栈上缓冲区的double格式化比 11.2 快了 60% 以上34.471ns → 21.000ns。12.2.0 又默认启用了完整 Dragonbox 查找表缓存平均每个double耗时降至 22.07ns与sprintf726.27ns和ostringstream864.34ns相比优势明显。仓库 doc/perf.svg 也直观对比了ostringstream、ostrstream、sprintf、doubleconv与fmt在 double to string 场景下的耗时时间越短越好fmt 的条形最短。Dragonbox 是 {fmt} 用于最短浮点表示的默认算法Grisu 已在 10.0 中被替换10.0 还为其增加了“给定精度”下的新算法。注意这些数据均来自特定平台如 Apple M1 Pro clang 17的 dtoa-benchmark实际数值会因平台与编译选项而异结论请以自身环境实测为准。编译期格式化与运行时分派8.0.0 起默认开启编译期格式字符串检查在支持 C20consteval的编译器上gcc 10、clang 11fmt::print({:d}, I am not a number)会直接编译报错。需要运行时字符串时用fmt::runtime包裹fmt::print(fmt::runtime({:d}), I am not a number);8.0.0 同时引入FMT_COMPILE宏把格式字符串编译为类型化代码十六进制格式化{:x}提速 3–7 倍_cf字面量则提供更简洁的写法需要 gcc 9.3 对类类型作为非类型模板参数的支持#include fmt/compile.h using namespace fmt::literals; auto s fmt::format(FMT_COMPILE({}), 42); // 宏写法 auto s fmt::format({}_cf, 42); // UDL 写法这些接口在 include/fmt/compile.h 中实现FMT_COMPILE(s)在可用时展开为FMT_STRING_IMPL(s, fmt::compiled_string)operator_cf则基于detail::fixed_string模板参数返回编译期字符串。12.0.0 把编译期能力推到新高度fmt::format支持constexpr在std::string支持 constexpr 的前提下fmt::format(_cf, 42)可在编译期完成FMT_STATIC_FORMAT在编译期把格式化结果放进“尺寸恰好合适”的字符串中。ChangeLog 中的示例constexpr auto s FMT_STATIC_FORMAT({}, 42);编译后直接生成.asciiz 42可通过s.c_str()或s.str()访问。其实现位于 include/fmt/compile.h 第 594–600 行附近用fmt::formatted_size(FMT_COMPILE(fmt_str), ...) 1在编译期推算所需大小再实例化静态存储的格式化结果。配套地9.1.0 让fmt::formatted_size支持编译期求值constexpr size_t n fmt::formatted_size({}_cf, 42);输出 29.0.0 让编译期浮点格式化不再依赖 header-only 模式。8.0.0 还要求用户自定义类型的formatter::format为const成员函数以与std::format保持一致——从源码结构看这是 format string compilation 能够生成常量求值代码的前提。其他 12.x 性能点12.1.0 优化buffer::append在 spdlog 基准上带来最高约 16% 的提升11.0.0 起fmt::print在常见场景直接写入 C 流缓冲区减少动态内存分配简单基准中从 10.x 的 63.8ns 降到 51.3ns12.2.0 针对 back-insert iterator 采用批量append/insert如std::vectorchar调试构建二进制体积从约 200k 降到约 85kbloat 测试并在没有consteval时提升编译速度。编译期检查与格式字符串的演进默认开启的编译期检查与FMT_STRING8.0.0 之前编译期检查需要显式使用FMT_STRING宏之后默认启用。12.2.0 进一步规定当FMT_USE_CONSTEVAL启用时FMT_STRING成为空操作no-op因为 consteval 格式字符串构造函数本身已提供编译期校验——也就是说只要编译器支持检查机制完全内建于类型系统中无需宏参与。具名参数与重复检测11.2.0 修复了格式说明符中具名参数的处理并新增重复具名参数的错误报告8.0.0 为FMT_COMPILE增加 UDL 具名参数支持参数在编译期解析、零运行时开销#include fmt/compile.h using namespace fmt::literals; auto s fmt::format(FMT_COMPILE({answer}), answer_a 42);12.2.0 补齐了编译期格式字符串的具名参数校验此前存在缺失并把fmt::named_arg提升为公开 API。8.1.0 还实现了基于 UDL 的具名参数编译期检查fmt::print({answer:s}, answer_a42)会在编译期报错因为整数不支持s说明符。格式字符串的 NUL 与 printf 语义12.2.0 修复了编译期格式字符串检查在嵌入 NUL 字节时截断字符串字面量的问题12.1.0 及之前版本还修复了printf格式化中的越界读取12.2.0 的修复见 ChangeLog.md 相关条目。12.0.0 移除了fmt::printf对格式字符串 NUL 结尾的假设12.2.0 起fmt::printf支持位置参数作为宽度/精度说明符。printf相关实现集中在 include/fmt/printf.h测试见 test/printf-test.cc。新增 formatter 全家桶标准库类型覆盖ChangeLog 展示了 {fmt} 对标准库类型的持续覆盖绝大多数 formatter 位于 include/fmt/std.h 与 include/fmt/ranges.h异常体系10.0.0 新增std::exceptionformatter输出如vectorbool::_M_range_check: ...12.2.1 扩展到std::exception_ptr与嵌套异常展开std::expected11.1.0 支持std::expectedvoid, E打印expected()10.0.0 支持std::optionalchrono 日历类型11.0.0 支持std::chrono::day/month/year/year_month_day配合 include/fmt/color.h 可输出彩色日期路径与文件系统9.0.0 起支持std::filesystem::path10.2.0 增加g表示Windows 下C:\foo→C:/foo12.2.0 保证路径格式化无损保留 ill-formed UTF-16 序列std::variant9.0.0、std::complex11.0.0并退出 tuple 格式化路径、std::type_info11.0.0、std::source_location10.2.0输出file:line:col: function、std::bitset10.2.0fmt::print({}, std::bitset6(42));输出101010、std::thread::id9.0.0容器适配器10.0.0 支持std::priority_queue、std::queue、std::stack错误码11.2.0 为std::error_code新增s说明符输出错误消息字符串平台相关11.1.0 为其增加宽度与对齐支持代理引用10.1.0 支持std::vectorbool与std::bitsetN的代理引用元素。格式化自定义类型的推荐路径也在演进9.0.0 提供 ADL 查找的format_as扩展点任何用户定义类型皆可用不限于枚举fmt::ostream_formatter与fmt::streamed则用于复用operator。12.2.1 已把fmt::streamed从 C20 模块中导出。ranges 格式化与 fmt::join 的完善范围格式化能力同样在历次版本中逐步增强实现在 include/fmt/ranges.h8.1.0 为字符串范围元素实现转义输出[\naan]并切换到 JSON 风格的 map/set 表示{answer: 42}与 Pythonstr.format对齐9.1.0 新增n说明符禁用分隔符输出fmt::print({:n}\n, std::vector{1, 2, 3});输出1, 2, 39.0.0 支持嵌套说明符fmt::print({::#x}\n, std::vector{10, 20, 30});输出[0xa, 0x14, 0x1e]11.1.0 为 tuple 与 pair 新增n说明符fmt::join支持 tuple-like 类型12.2.0 为fmt::join支持wchar_t等非char分隔符且弃用std::initializer_list重载8.0.0 将范围分隔符从{}改为[]并移除了范围元素数量上限。chrono 格式化行为与语义的变迁include/fmt/chrono.h 是历次版本的重点默认本地化8.0.0 起更多 chrono 说明符默认与 locale 无关需显式L说明符启用本地化如fmt::print({:L}\n, monday);在 ru_RU 下输出пнUTC 语义10.0.0 将std::chrono::system_clock格式化从本地时间改为 UTC以对齐标准11.2.0 修复了std::chrono::local_time与tm的跨平台一致性并为缺少时区信息的情况提供编译期诊断fmt::print({:Z}, std::chrono::local_seconds());直接编译报错亚秒与精度8.1.0 实现 chrono 时长亚秒格式化{:%S}配合std::chrono::milliseconds(1234)输出01.23410.0.0 为%S增加精度支持并实现 subseconds 格式化还修复了 epoch 之前时间点的输出59.750000000性能8.1.0 优化 chrono 格式化%z/%Y处理快 10–20 倍261ns → 26.3ns日期单位10.2.0 为std::chrono::duration支持%j天数并修正单位后缀std::chrono::days(42)输出42d分钟后缀改为min12.2.0 修复了 chrono 格式化中超出范围的浮点时长。Unicode、宽度与本地化11.0.0 在 MSVC 上默认启用 Unicode 支持可用 CMake 选项FMT_UNICODE控制避免路径与终端输出出现乱码12.0.0 起精度使用“估算显示宽度”fmt::print(|{:.4}|\n|1234|\n, )因 emoji 估算宽度为 2 而输出 4 个位置8.1.0 起fmt::group_digits提供非本地化的三位分组fmt::print({} dollars, fmt::group_digits(1000000));输出1,000,000 dollars8.0.0 允许L说明符与演示类型组合{0:.2Lf}在 fr_FR 下输出0,42并移除了旧的n说明符8.0.0 起默认浮点输出不再带尾随零{0:.3}对 1.1 输出1.1保留尾随零需#12.2.0 修复了std::tm中tm_zone为空时的格式化并明确了十六进制浮点a/A始终输出0x前缀见 include/fmt/format.h 相关文档。输出与文本样式print、println、styled8.1.0 新增fmt::styled对单个参数应用样式fmt::styled(error, fg(fmt::color::red))并支持 faint/conceal/reverse/blink 等文本样式include/fmt/color.h10.0.0 加入fmt::println对齐 C2312.2.0 为其增加接受fmt::text_style的重载11.0.0 起fmt::print可直接写入 C 流缓冲区常见场景消除缓冲层动态分配9.0.0 弃用通过fmt/ostream.h自动发现operator的行为防止 ODR 违规改用fmt::streamed或fmt::ostream_formatterfmt::ostream_formatter的用法示例见 include/fmt/ostream.h 文档与 ChangeLog 9.0.0 条目template struct fmt::formatterdate : ostream_formatter {};。构建系统与兼容性要点CMake 选项从 CMakeLists.txt 可以看到当前仓库支持的构建选项选项默认值说明FMT_DOC随FMT_MASTER_PROJECT是否生成 doc 目标FMT_INSTALL随FMT_MASTER_PROJECT是否生成安装目标作为子项目时默认关闭FMT_TEST随FMT_MASTER_PROJECT是否生成测试目标FMT_FUZZOFF是否生成 fuzz 目标FMT_CUDA_TESTOFF是否生成 cuda-test 目标FMT_OSON是否包含 OS 相关 APIFMT_MODULE随FMT_USE_MODULES是否构建 C20 module 库FMT_SYSTEM_HEADERSOFF是否把 {fmt} 头文件标记为系统头抑制警告FMT_UNICODEON是否启用 Unicode 支持FMT_PEDANTICOFF启用额外警告与昂贵测试FMT_WERROR-编译器警告按错误处理其中FMT_UNICODEOFF时定义FMT_UNICODE0fmt-header-only目标默认定义FMT_HEADER_ONLY1。12.0.0 将组件前缀从fmt-改为fmt_如fmt-doc→fmt_doc以兼容 Windows 上的 NSIS/CPack11.1.1 定义了core与doc组件允许单独安装文档。头文件布局的破坏性变更12.2.0fmt/core.h默认等价于fmt/base.h不再隐式包含fmt/format.h可用FMT_DEPRECATED_HEAVY_CORE恢复旧行为std::byteformatter 移到fmt/std.h11.0.0新增 include/fmt/base.h提供最小包含依赖的 API 子集可完全替代printf家族100 个源文件的编译基准中fmt 11.0 为 4.8s而 10.x 为 19.0sprintf为 1.6sIOStreams 为 25.9s8.0.0fmt/posix.h更名为fmt/os.hfmt/locale.h在 9.0.0 移除locale 相关重载迁入fmt/format.h与fmt/xchar.hwchar_t专属 API 迁入fmt/xchar.h。破坏性移除清单12.0.0has_formatter改用is_formattablebasic_format_args::parse_context_type、formatter_type等上下文类型别名宽流版本的fmt::printf与带文本样式的宽流fmt::printis_*chartraits 与fmt::localtime改用std::localtime宽流版本的fmt::fprintf/fmt::sprintf被弃用9.0.0 移除的_format、arg_join、接收 memory buffer 的format_to重载等旧 API。测试、安全与仓库配套资源仓库提供了覆盖上述特性的完整测试套件test/format-test.cc、test/chrono-test.cc、test/ranges-test.cc、test/printf-test.cc、test/std-test.cc、test/xchar-test.cc 等针对 C API 的测试位于 test/c-test.c。12.2.0 起 CI 还增加了 SLSA provenance 产物与 CodeQL 工作流、.github/SECURITY.md安全策略并有 fuzzing 目标test/fuzzing覆盖 chrono duration/timepoint、浮点、具名参数等场景文档源码位于 doc含 doc/api.md、doc/syntax.md、doc/get-started.md更早版本0.8.0–7.1.3的变更记录可查看 doc/ChangeLog-old.md头文件可通过 include/fmt/format.h 直接包含header-only 模式或通过 CMake 链接fmt::fmt/fmt::fmt-header-only/fmt::fmt-module目标使用。升级建议与迁移清单若仍在使用fmt/core.h且依赖format.h的内容请显式包含fmt/format.h或临时定义FMT_DEPRECATED_HEAVY_CORE把has_formatter替换为is_formattable把fmt::localtime替换为std::localtime移除is_*chartraits 的使用为枚举与自定义类型的隐式转换改用format_as为需要operator格式化的类型改用fmt::streamed或fmt::ostream_formatter确保自定义 formatter 的format成员为const以兼容编译期格式化与std::format语义检查宽流printf/fprintf/sprintf的使用迁移到窄字符重载或fmt::print若在 C 项目中需要类型安全格式化可引入fmt-c库#include fmt/fmt-c.h注意 MSVC 下需/Zc:preprocessor需要极致性能的场景优先使用FMT_COMPILE/_cf编译期格式化配合FMT_STATIC_FORMAT消除运行时分配需要最小二进制体积时避免定义__OPTIMIZE_SIZE__并评估FMT_USE_FULL_CACHE_DRAGONBOX相关缓存策略。以上所有结论均可在 ChangeLog.md、include/fmt 头文件、src 实现与 test 测试中找到对应证据具体性能数据依赖编译环境请以官方 dtoa-benchmark 或自身基准为准。【免费下载链接】fmtA modern formatting library项目地址: https://gitcode.com/GitHub_Trending/fm/fmt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考 网站设计 视觉排版 运营推广 返回列表