std::format / std::print
What problem does this section solve?
Formatting strings in C++ has always been a bit cumbersome:
printf: fast but type-unsafe, format string errors can cause crashes.std::cout:Type-safe but verbose to write and inconvenient for format control.std::stringstream: Full-featured but verbose.
C++20/23 introduced std::format (for formatted strings) and std::print (for direct output), combining Python-like simplicity with C++'s type safety and high performance.
What is this feature?
std::format(C++20): similar to Python'sf"{name}: {score}", returns the formattedstd::string.std::print(C++23): Similar to Python'sprint(), it directly outputs formatted results to stdout.
Based on the {fmt} library, it delivers exceptional performance—on par with or even exceeding printf.
C++ standard version
std::format:C++20std::print:C++23
Required header files
#include <format> // for std::format (C++20)
#include <print> // for std::print, std::println (C++23)
Basic Syntax
// std::format:返回 string
std::string s = std::format("Hello, {}!", name);
std::string s2 = std::format("{0} + {1} = {2}", a, b, a + b);
// std::print:直接输出(不自动换行)
std::print("x = {}, y = {}", x, y);
// std::println:输出并换行
std::println("Hello, {}!", name);
// 指定输出目标:stdout / stderr 是 FILE*
std::println(stdout, "normal message");
std::println(stderr, "error message");
// 格式控制
std::format("{:.2f}", 3.14159); // "3.14" —— 保留 2 位小数
std::format("{:>10}", 42); // " 42" —— 右对齐,宽度 10
std::format("{:<10}", 42); // "42 " —— 左对齐
std::format("{:^10}", 42); // " 42 " —— 居中
std::format("{:#x}", 255); // "0xff" —— 十六进制带前缀
std::format("{:04d}", 7); // "0007" —— 前导零填充
Output Mode Comparison
| method | performance | Type safety | concise | Version Information |
|---|---|---|---|---|
printf | Fast | ❌ | ✅ | C |
std::cout | slow | ✅ | ❌ | C++98 |
std::format | Very quickly | ✅ | ✅ | C++20 |
std::print | Very quickly | ✅ | ✅ | C++23 |
std::print outputs to the standard output stream (stdout) by default, similar to std::cout. You can customize the destination by providing a FILE* or std::FILE* as the first argument.
In the C++23 standard library, the identifiers std::print and std::println are commonly used in two typical patterns:
| writing method | Output target |
|---|---|
std::println("x = {}", x) | Outputs to standard output by default, which is stdout |
std::println(stdout, "x = {}", x) | Explicitly output to stdout |
std::println(stderr, "error = {}", code) | output to standard error stderr |
Here, stdout and stderr are FILE* in the C standard library, so you need to include <cstdio>.
Note: In standard C++23, the first parameter of std::println is not std::cout. std::cout is a C++ std::ostream object belonging to the <iostream> namespace. You might have encountered similar fmt::print(std::cout, "...") syntax in certain libraries or extensions, but that interface is not the same as the one provided by the standard library std::println.
Example code
Example 1: basic usage of std::format
#include <iostream>
#include <format>
#include <string>
int main()
{
std::string name = "Alice";
int age = 25;
double score = 92.5;
// 基本占位符
std::string s1 = std::format("Name: {}, Age: {}, Score: {}", name, age, score);
std::cout << s1 << "\n";
// 指定顺序
std::string s2 = std::format("{1} is {0} years old", age, name);
std::cout << s2 << "\n";
// 保留 2 位小数
std::string s3 = std::format("Score: {:.2f}", score);
std::cout << s3 << "\n";
return 0;
}
Results:
Name: Alice, Age: 25, Score: 92.5
Alice is 25 years old
Score: 92.50
Example 2: Building on Example 1, format control and alignment
#include <iostream>
#include <format>
int main()
{
// 右对齐,宽度 10
std::cout << std::format("[{:>10}]\n", 42);
// 左对齐,宽度 10
std::cout << std::format("[{:<10}]\n", 42);
// 居中,宽度 10
std::cout << std::format("[{:^10}]\n", 42);
// 前导零
std::cout << std::format("{:05d}\n", 7);
// 十六进制
std::cout << std::format("hex = {:#x}, oct = {:#o}\n", 255, 255);
// 打印一个简单的表格
std::cout << std::format("{:<10} {:>5} {:>7}\n", "Name", "Age", "Score");
std::cout << std::format("{:<10} {:>5} {:>7.1f}\n", "Alice", 25, 92.5);
std::cout << std::format("{:<10} {:>5} {:>7.1f}\n", "Bob", 22, 88.0);
std::cout << std::format("{:<10} {:>5} {:>7.1f}\n", "Charlie", 24, 78.5);
return 0;
}
Results:
[ 42]
[42 ]
[ 42 ]
00007
hex = 0xff, oct = 0377
Name Age Score
Alice 25 92.5
Bob 22 88.0
Charlie 24 78.5
Example 3: std::print Direct Output (C++23)
#include <cstdio>
#include <print>
#include <string>
int main()
{
std::string name = "World";
int value = 42;
// 直接输出,不换行
std::print("Hello, ");
std::print("{}", name);
std::print("!\n");
// 输出到 stdout 并换行
std::println("The answer is {}", value);
// 第一个参数也可以显式写 stdout
std::println(stdout, "stdout: {}", name);
// 带格式输出
std::println("pi = {:.3f}", 3.1415926);
// 输出到 stderr
std::println(stderr, "Error: something went wrong!");
return 0;
}
Results:
Hello, World!
The answer is 42
stdout: World
pi = 3.142
Error: something went wrong!
runtime results
See the "running results" for each example above.
Key syntax explanation in the example
|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.
| Example | Discusses what | Newly emerged syntax | Why write it this way | Precautions |
|---|---|---|---|---|
| Example 1 | format basic usage | std::format("...", arg1, arg2), {} placeholders | Python style + C++ type safety | The number of parameters must match the count of {} placeholders. |
| Example 2 | Formatting Control and Tables | {:>10}、{:.2f}、{:#x} | Built-in format specifiers are richer than printf. | The format control characters are inside {} and after :. |
| Example 3 | print/println direct output | std::println()、std::print()、stdout、stderr | No need for std::cout, just format the output directly. | The standard interface receives FILE*, not std::cout. |
Common Errors
Error 1: Missing the index before the format specifier :
std::format("{.2f}", 3.14); // ❌ 缺少 : 前的占位符
Correct approach: std::format("{:.2f}", 3.14); or std::format("{}", 3.14);
Error 2: Parameter count mismatch
std::format("{}, {}", 1); // ❌ 有 2 个占位符,只有 1 个参数
Compilation errors occur here (which is where format is safer than printf).
Error 3: Strings output with format contain { or }
std::format("Set = {1, 2, 3}"); // ❌ {1, 2, 3} 会被误解为格式说明
Correct approach: use {{ to represent the literal value {, and }} to represent the literal value }:
std::format("Set = {{1, 2, 3}}"); // 输出:Set = {1, 2, 3}
使用建议
- 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
- 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
- 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
- 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
- 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。
如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。
- C++20 Project Replaces
stringstreamandsprintfwithstd::format: Cleaner code, type-safe, and high performance. - C++23 Project Simplifies Formatting Output with
std::print/std::println:Output defaults tostdout, and you can also passstderr. - Format specifiers are similar to Python: If you are familiar with Python's formatting syntax, it is easy to pick up.
- If your compiler doesn't support C++20/23 yet, you can use the
{fmt}library (https://github.com/fmtlib/fmt),它是标准化的基础。
Summary
std::format("{} + {} = {}", a, b, c)returns formatted strings.std::print("...")/std::println("...")directly outputs tostdout.std::println(stderr, "...")can output to standard error.- Type-Safe + Powerful Formatting + High Performance: Combines the speed of printf with the safety of cout.
- Formatting controls:
{:.2f}decimal places,{:>10}alignment,{:#x}base,{:04d}zero-padding.