String Formatting Quick Reference
C++ string formatting cheat sheet — std::format, std::print, format specifiers, custom formatters, and migration from printf/sprintf/ostringstream.
Quick Start
cpp
#include <format> // C++20
#include <print> // C++23
std::string s = std::format("Hello, {}! x={}", name, 42);
std::println("result: {:.2f}", 3.14159); // to stdout with newline
std::print(stderr, "Error: {}\n", msg); // to fileFormat Specifiers
cpp
{[arg_id][:[fill][align][sign][#][0][width][.precision][type]]}Width and Alignment
cpp
std::format("{:10}", "hello") // "hello " left-aligned (default for strings)
std::format("{:<10}", "hello") // "hello " left
std::format("{:>10}", "hello") // " hello" right
std::format("{:^10}", "hello") // " hello " center
std::format("{:*^10}", "hello") // "**hello***" center with fill char '*'
std::format("{:10}", 42) // " 42" right-aligned (default for integers)
std::format("{:<10}", 42) // "42 "Integer Types
cpp
std::format("{}", 255) // "255" decimal (default)
std::format("{:d}", 255) // "255" decimal explicit
std::format("{:x}", 255) // "ff" hex lowercase
std::format("{:X}", 255) // "FF" hex uppercase
std::format("{:o}", 255) // "377" octal
std::format("{:b}", 255) // "11111111" binary
std::format("{:#x}", 255) // "0xff" hex with prefix
std::format("{:#b}", 8) // "0b1000" binary with prefix
std::format("{:08x}", 255) // "000000ff" zero-padded width 8
std::format("{:+}", 42) // "+42" force sign
std::format("{: }", 42) // " 42" space for positiveFloating Point
cpp
std::format("{}", 3.14) // "3.14"
std::format("{:.2f}", 3.14159) // "3.14" fixed, 2 decimal places
std::format("{:.4e}", 3.14159) // "3.1416e+00" scientific notation
std::format("{:.4g}", 3.14159) // "3.142" shortest of f or e
std::format("{:.4a}", 1.0) // "0x1.0000p+0" hex float
std::format("{:10.2f}", 3.14) // " 3.14" width + precision
std::format("{:+.2f}", 3.14) // "+3.14" force sign
std::format("{:010.2f}", 3.14) // "0000003.14" zero-paddedStrings
cpp
std::format("{}", "hello") // "hello"
std::format("{:10}", "hello") // "hello " padded to 10
std::format("{:.3}", "hello") // "hel" max 3 chars
std::format("{:?}", "he\nllo") // "\"he\\nllo\"" debug/escaped (C++23)Booleans
cpp
std::format("{}", true) // "true"
std::format("{:d}", true) // "1" as integer
std::format("{:s}", true) // "true" explicit stringPositional and Named Arguments
cpp
// Positional (0-indexed)
std::format("{0} {1} {0}", "a", "b") // "a b a"
// Cannot mix positional and auto-numbered in one format stringstd::print / std::println (C++23)
cpp
#include <print>
std::print("no newline: {}", x);
std::println("with newline: {}", x); // appends \n
std::println(stderr, "error: {}", msg); // to stderr
std::println(file, "record: {}", data); // to FILE* or ostreamFormatting to a Buffer
cpp
// Format into a string
std::string s = std::format("{} + {} = {}", 1, 2, 3);
// Format into existing buffer (avoids allocation)
std::string buf;
buf.reserve(256);
std::format_to(std::back_inserter(buf), "{:08x}", 0xDEAD);
// With size limit
char arr[32];
auto result = std::format_to_n(arr, sizeof(arr) - 1, "{}", value);
arr[result.size] = '\0';
// Count required chars (no output)
size_t needed = std::formatted_size("{:.2f}", 3.14159);Custom Formatter
cpp
struct Point { double x, y; };
template<>
struct std::formatter<Point> {
// Parse format spec (e.g., "{:.2f}")
double precision = -1;
constexpr auto parse(std::format_parse_context& ctx) {
auto it = ctx.begin();
// optionally parse custom specs from [it, ctx.end())
return it; // return iterator past parsed spec
}
// Format the value
auto format(const Point& p, std::format_context& ctx) const {
return std::format_to(ctx.out(), "({}, {})", p.x, p.y);
}
};
std::println("point: {}", Point{1.5, 2.7}); // "point: (1.5, 2.7)"Reusing existing formatters
cpp
template<>
struct std::formatter<Color> : std::formatter<std::string_view> {
auto format(Color c, std::format_context& ctx) const {
std::string_view name = "unknown";
switch (c) {
case Color::Red: name = "Red"; break;
case Color::Green: name = "Green"; break;
case Color::Blue: name = "Blue"; break;
}
return std::formatter<std::string_view>::format(name, ctx);
}
};Migration Guide
From printf
cpp
// printf
printf("x=%d, y=%.2f, s=%s\n", x, y, s.c_str());
// std::format
std::println("x={}, y={:.2f}, s={}", x, y, s);From sprintf
cpp
// sprintf (unsafe — buffer overflow risk)
char buf[256];
sprintf(buf, "%08x", value);
// std::format (safe)
std::string s = std::format("{:08x}", value);From ostringstream
cpp
// ostringstream
std::ostringstream oss;
oss << std::setw(10) << std::setprecision(2) << std::fixed << x;
std::string s = oss.str();
// std::format
std::string s = std::format("{:10.2f}", x);From the {fmt} library
cpp
// {fmt} (same syntax — std::format is based on it)
fmt::format("hello {}", name);
fmt::print("result: {:.2f}", x);
// std::format (drop-in for most cases)
std::format("hello {}", name);
std::print("result: {:.2f}", x);Common Patterns
cpp
// Hex dump
for (size_t i = 0; i < data.size(); ++i) {
std::print("{:02x}", data[i]);
if ((i + 1) % 16 == 0) std::println();
else if ((i + 1) % 8 == 0) std::print(" ");
else std::print(" ");
}
// Table formatting
std::println("{:<20} {:>10} {:>8}", "Name", "Score", "Rank");
std::println("{:-<20} {:->10} {:->8}", "", "", "");
for (auto& [name, score, rank] : results)
std::println("{:<20} {:>10} {:>8}", name, score, rank);
// Timestamp
auto now = std::chrono::system_clock::now();
std::println("{:%Y-%m-%d %H:%M:%S}", now); // 2025-01-15 14:30:00