fmt

Library

fmtlib/fmt

A modern C++ formatting library providing fast, safe alternatives to printf and iostreams.

Overview

fmt is an open-source C++ formatting library that implements C++20 std::format and C++23 std::print. It offers a Python-like format syntax with positional arguments, supports user-defined types, Unicode, chrono, and ranges. The library is type-safe, highly performant, and available as a header-only config.

README Preview

\n\n[](\nhttps://github.com/fmtlib/fmt/actions?query=workflow%3Alinux)\n[](\nhttps://github.com/fmtlib/fmt/actions?query=workflow%3Amacos)\n[](\nhttps://github.com/fmtlib/fmt/actions?query=workflow%3Awindows)\n[](\nhttps://issues.oss-fuzz.com/issues?q=title:fmt%20cc:victor.zverovich@gmail.com)\n[](\nhttps://www.bestpractices.dev/projects/8880)\n[](\nhttps://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt)\n[](https://stackoverflow.com/questions/tagged/fmt)\n[](https://novaukraine.org/)\n\n**{fmt}** is an open-source formatting library providing a fast and safe\nalternative to C stdio and C++ iostreams.\n\n[Documentation](https://fmt.dev)\n\n[Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html)\n\nQ&A: ask questions on [StackOverflow with the tag\nfmt](https://stackoverflow.com/questions/tagged/fmt).\n\nTry {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v).\n\n# Features\n\n- Simple [format API](https://fmt.dev/latest/api/) with positional\n  arguments for localization\n- Implementation of [C++20\n  std::format](https://en.cppreference.com/w/cpp/utility/format) and\n  [C++23 std::print](https://en.cppreference.com/w/cpp/io/print)\n- [Format string syntax](https://fmt.dev/latest/syntax/) similar\n  to Python\'s\n  [format](https://docs.python.org/3/library/stdtypes.html#str.format)\n- Fast IEEE 754 floating-point formatter with correct rounding,\n  shortness and round-trip guarantees using the\n  [Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm\n- Portable Unicode support\n- Safe [printf\n  implementation](https://fmt.dev/latest/api/#printf-api)\n  including the POSIX extension for positional arguments\n- Extensibility: [support for user-defined\n  types](https://fmt.dev/latest/api/#formatting-user-defined-types)\n- High performance: faster than common standard library\n  implementations of `(s)printf`, iostreams, `to_string` and\n  `to_chars`, see [Speed tests](#speed-tests) and [Converting a\n  hundred million integers to strings p

FAQ (5)

Troubleshooting
Why does {fmt} escape newer emoji and CJK characters as \Uxxxxxxxx in `{:?}` and vector/range output, and how do I fix it?

This occurs because fmt::detail::is_printable was generated from Unicode 13.0 data. Code points added in Unicode 14.0–17.0, such as 🫠 U+1FAE0 and CJK Extensions H/I/J, are incorrectly classified as unassigned (Cn) and therefore escaped. Update {fmt} to a release or commit containing the Update is_printable to Unicode 17.0 fix. If maintaining a fork, regenerate the table from Unicode 17.0.0 UnicodeData.txt by running python3 support/printable.py—updating the script’s Unicode version/data URL if it is pinned—and replace the generated is_printable code, then rebuild. Afterward, fmt::print("{:?}\n", "🫠") outputs "🫠" instead of "\U0001fae0".

GitHub Issue #4961
Troubleshooting
How to fix MSVC warning C4702 (unreachable code) in fmt/ranges.h when compiling with /W4?

This is a known MSVC false positive triggered by fmt 12.2.0's range formatter. Patch the formatter() constructor in include/fmt/ranges.h so set_brackets() is in an else branch:

FMT_CONSTEXPR formatter() {
  if FMT_CONSTEXPR20 (range_format_kind<R, Char>::value != range_format::set)
    return;
  else
    range_formatter_.set_brackets(detail::string_literal<Char, '{'>{},
                                  detail::string_literal<Char, '}'>{});
}

Then rebuild. As a temporary workaround, you can disable the warning for the third-party header with #pragma warning(disable: 4702) or compile with /wd4702, but applying the patch or upgrading to a fmt release containing the fix is preferred.

GitHub Issue #4930
Troubleshooting
How do I fix a Git submodule that cannot check out a commit referenced by a release tag?

Fetch tags in all submodules before updating them:

git submodule foreach --recursive 'git fetch --tags'
git submodule update --recursive

This is needed when the submodule points to a tag whose commit is not reachable from any configured branch. A permanent fix is for the maintainer to tag the release on a maintained branch or create a separate release branch.

GitHub Issue #412
Troubleshooting
How do I fix fmt's `{:L}` specifier using comma grouping or the global locale when `FMT_USE_LOCALE=0`?

This was an fmt bug: with locale support disabled, {:L} was ignored for integers, used a hard-coded comma fallback for floating-point values, and some chrono formatters consulted std::locale(), which is the global locale. Update to an fmt release containing the fixes for issue #4941, or apply the upstream changes "Use classic locale grouping without locale support" and "Don't require std::locale in chrono.h when FMT_USE_LOCALE is 0". After the fix, L is accepted but uses classic/C-locale semantics: fmt::format("{:L}", 1234567) remains 1234567, and fmt::format("{:L}", 1234.5) returns 1234.5 without comma grouping. Define the macro before including fmt, for example with C++: #define FMT_USE_LOCALE 0 before #include <fmt/...>, or CMake: target_compile_definitions(my_target PRIVATE FMT_USE_LOCALE=0), then rebuild. On affected versions, remove L from format strings as a workaround. If you need locale-specific numbers or chrono names, build with FMT_USE_LOCALE=1 and pass the desired std::locale explicitly to fmt::format.

GitHub Issue #4941
Troubleshooting
How to fix Clang 15–20 segmentation fault when using fmt::format_as with a type derived from std::array?

The type is both a range because it inherits std::array and has a format_as overload, so {fmt}'s range formatter and format_as support are ambiguous. Clang crashes instead of reporting the ambiguity. Resolve it by providing an explicit fmt::formatter specialization for your type:

#include <fmt/format.h>

template <>
struct fmt::formatter<Sha256Hash> : fmt::formatter<std::string>
{
    auto format(const Sha256Hash& h, fmt::format_context& ctx) const
    {
        return fmt::formatter<std::string>::format(format_as(h), ctx);
    }
};

Alternatively, remove format_as if you want the default range formatting, or use composition instead of publicly inheriting std::array so the type is not recognized as a range. The Clang segfault itself is a compiler bug in Clang 15 through 20, but the ambiguity is the underlying source issue.

GitHub Issue #4943