Skip to main content

Format strings and arguments

A format string is a template with holes in it. Everything else in fmt — the spec grammar, custom formatters, compile-time checks — is about what you're allowed to write inside a hole, and where the result ends up going.

Replacement fields

{} consumes the next argument in order. {0}, {1}, ... pick an argument by explicit index. {:spec} attaches a format spec to either form.

fmt::format("{} + {} = {}", 2, 3, 5); // "2 + 3 = 5"
fmt::format("{0} + {1} = {0}", "no", "wait"); // "no + wait = no"
fmt::format("{:.2f}", 3.14159); // "3.14"

Escaping

To print a literal brace, double it: {{ produces { and }} produces }.

fmt::format("{{{}}}", 42); // "{42}"

Automatic vs manual indexing

A single format string must use either automatic ({}) or manual ({0}, {1}) indexing throughout — not both.

Mixing automatic and manual indexing in one format string is an error — fmt rejects it
fmt::format("{} and {1}", a, b); // compile-time error: cannot switch from automatic to manual

Pick one style per string. This is deliberate: mixing them makes it ambiguous which argument index the automatic field would land on.

Argument types

fmt formats these out of the box, with no extra header beyond <fmt/format.h>:

TypeDefault output
Integers (int, long, unsigned, ...)Decimal
Floating point (float, double)Shortest round-trip representation
booltrue / false
charThe character itself
const char*, std::string, std::string_viewThe text, unquoted
void*0x + hex address
Formatting a raw pointer other than void* requires an explicit cast — fmt will not silently print an address
int* p = &x;
fmt::format("{}", p); // compile-time error
fmt::format("{}", static_cast<void*>(p)); // "0x7ffee3a1c04c"

This is intentional — printing an arbitrary typed pointer's address is rarely what you meant, and fmt would rather force the cast than guess.

What happens on a mismatch

If the format string is a compile-time-checked literal, a spec that doesn't apply to its argument's type is a compile error — you find out before the code ships. If the string is a runtime string (see below), the same mismatch throws fmt::format_error instead. See Compile-time format string checking for exactly which cases are checked and when.

Runtime format strings

fmt::runtime("...") explicitly opts a string out of compile-time checking — needed whenever the format string itself is not a literal known at compile time, such as one loaded from a config file or constructed at runtime.

A user-supplied string must go through fmt::runtime and should never be trusted as a format string

Passing untrusted input as the format string (as opposed to an argument) lets that input control which arguments get read and how — at best a crash, at worst information disclosure. Validate or whitelist runtime format strings before formatting with them, the same way you'd treat any other input from outside your trust boundary.

See also