第 18.17 節

std::format / std::print

0瀏覽次數0訪問次數--跳出率--平均停留

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's f"{name}: {score}", returns the formatted std::string.
  • std::print (C++23): Similar to Python's print(), 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++20
  • std::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

methodperformanceType safetyconciseVersion Information
printfFastC
std::coutslowC++98
std::formatVery quicklyC++20
std::printVery quicklyC++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 methodOutput 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.


ExampleDiscusses whatNewly emerged syntaxWhy write it this wayPrecautions
Example 1format basic usagestd::format("...", arg1, arg2), {} placeholdersPython style + C++ type safetyThe number of parameters must match the count of {} placeholders.
Example 2Formatting Control and Tables{:>10}{:.2f}{:#x}Built-in format specifiers are richer than printf.The format control characters are inside {} and after :.
Example 3print/println direct outputstd::println()std::print()stdoutstderrNo 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}

使用建议

  • 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
  • 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
  • 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
  • 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
  • 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。

如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。

  1. C++20 Project Replaces stringstream and sprintf with std::format: Cleaner code, type-safe, and high performance.
  2. C++23 Project Simplifies Formatting Output with std::print/std::println:Output defaults to stdout, and you can also pass stderr.
  3. Format specifiers are similar to Python: If you are familiar with Python's formatting syntax, it is easy to pick up.
  4. 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 to stdout.
  • 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.
音乐页