命名空间
变体
操作

标准格式规范

来自 cppreference.com
< cpp‎ | utility‎ | format
 
 
工具库
语言支持
类型支持 (基本类型,RTTI)
库特性测试宏 (C++20)
动态内存管理
程序工具
协程支持 (C++20)
可变参数函数
调试支持
(C++26)
三元比较
(C++20)
(C++20)(C++20)(C++20)
(C++20)(C++20)(C++20)
通用工具
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中已弃用)
整数比较函数
(C++20)(C++20)(C++20)   
(C++20)
交换类型操作
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
通用词汇类型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
基本字符串转换
(C++17)
(C++17)

 
 

对于基本类型和字符串类型,格式规范基于 Python 中的格式规范

格式规范的语法为

填充和对齐 (可选) 符号 (可选) #(可选) 0(可选) 宽度 (可选) 精度 (可选) L(可选) 类型 (可选)

当使用整数或浮点数表示类型时,符号#0 选项才有效。

内容

[编辑] 填充和对齐

填充和对齐 是一个可选的填充 字符(可以是除 {} 之外的任何字符),后跟一个对齐 选项 <>^

如果未指定填充字符,则默认为空格字符。对于 Unicode 编码中的格式规范,填充字符必须对应于单个 Unicode 标量值。

对齐 选项的含义如下

  • <: 强制格式化后的参数通过在格式化后的参数后插入 n 个填充字符来对齐到可用空间的开头。当使用非整数非浮点数表示类型时,这是默认值。
  • >: 强制格式化后的参数通过在格式化后的参数前插入 n 个填充字符来对齐到可用空间的结尾。当使用整数或浮点数表示类型时,这是默认值。
  • ^: 强制格式化后的参数通过在格式化后的参数前插入
    n
    2
    个字符,并在格式化后的参数后插入
    n
    2
    个字符来居中对齐到可用空间。

在每种情况下,n 是最小字段宽度(由 宽度 指定)和格式化后的参数的 估计宽度 之间的差值,如果差值小于 0,则为 0。

char c = 120;
assert(std::format("{:6}", 42)    == "    42");
assert(std::format("{:6}", 'x')   == "x     ");
assert(std::format("{:*<6}", 'x') == "x*****");
assert(std::format("{:*>6}", 'x') == "*****x");
assert(std::format("{:*^6}", 'x') == "**x***");
assert(std::format("{:6d}", c)    == "   120");
assert(std::format("{:6}", true)  == "true  ");

[编辑] 符号、# 和 0

符号 选项可以是以下之一

  • +: 表示对非负数和负数都应使用符号。对于非负数,+ 符号插入到输出值的前面。
  • -: 表示仅对负数应使用符号(这是默认行为)。
  • 空格: 表示对非负数应使用前导空格,对负数应使用减号。

负零被视为负数。

符号 选项适用于浮点数无穷大和小数。

double inf = std::numeric_limits<double>::infinity();
double nan = std::numeric_limits<double>::quiet_NaN();
assert(std::format("{0:},{0:+},{0:-},{0: }", 1)   == "1,+1,1, 1");
assert(std::format("{0:},{0:+},{0:-},{0: }", -1)  == "-1,-1,-1,-1");
assert(std::format("{0:},{0:+},{0:-},{0: }", inf) == "inf,+inf,inf, inf");
assert(std::format("{0:},{0:+},{0:-},{0: }", nan) == "nan,+nan,nan, nan");

# 选项会导致对转换使用备用形式

  • 对于整数类型,当使用二进制、八进制或十六进制表示类型时,备用形式会在符号字符(可能是空格)后(如果存在)或在输出值之前(如果不存在)将前缀 (0b00x) 插入到输出值中。
  • 对于浮点类型,备用形式会导致有限值的转换结果始终包含一个小数点字符,即使没有数字在它之后。通常,这些转换结果中只在数字紧随其后时才会出现小数点字符。此外,对于 gG 转换,不会从结果中删除尾随零。

0 选项会用前导零(在任何符号或基数指示符之后)填充字段,直到达到字段宽度,除非它应用于无穷大或小数。如果 0 字符和对齐 选项都出现,则忽略 0 字符。

char c = 120;
assert(std::format("{:+06d}", c)   == "+00120");
assert(std::format("{:#06x}", 0xa) == "0x000a");
assert(std::format("{:<06}", -42)  == "-42   "); // 0 is ignored because of < alignment

[编辑] 宽度和精度

宽度 是一个正十进制数,或一个嵌套的替换字段 ({}{n})。如果存在,它指定最小字段宽度。

精度 是一个点 (.),后跟一个非负十进制数或一个嵌套的替换字段。此字段表示精度或最大字段大小。它只能与浮点类型和字符串类型一起使用。

  • 对于浮点类型,此字段指定格式化精度。
  • 对于字符串类型,它提供了要复制到输出的字符串前缀的估计宽度(见 下文)的上限。对于 Unicode 编码中的字符串,要复制到输出的文本是估计宽度不超过精度的最长完整扩展字形簇前缀。

如果嵌套替换字段用于 widthprecision,并且相应的参数不是 整数类型(直到 C++23)标准有符号或无符号整数类型(从 C++23 起),或者为负数,则抛出类型为 std::format_error 的异常。

float pi = 3.14f;
assert(std::format("{:10f}", pi)           == "  3.140000"); // width = 10
assert(std::format("{:{}f}", pi, 10)       == "  3.140000"); // width = 10
assert(std::format("{:.5f}", pi)           == "3.14000");    // precision = 5
assert(std::format("{:.{}f}", pi, 5)       == "3.14000");    // precision = 5
assert(std::format("{:10.5f}", pi)         == "   3.14000"); // width = 10, precision = 5
assert(std::format("{:{}.{}f}", pi, 10, 5) == "   3.14000"); // width = 10, precision = 5
 
auto b1 = std::format("{:{}f}", pi, 10.0); // throws: width is not of integral type 
auto b2 = std::format("{:{}f}", pi, -10);  // throws: width is negative
auto b3 = std::format("{:.{}f}", pi, 5.0); // throws: precision is not of integral type

字符串的宽度定义为在终端中显示它所需的估计列数。

为了进行宽度计算,假设字符串使用实现定义的编码。宽度计算方法未指定,但对于使用 Unicode 编码的字符串,实现应该将字符串的宽度估计为其 扩展字形簇 中第一个代码点的估计宽度的总和。以下代码点的估计宽度为 2,否则为 1

  • 任何代码点,其 Unicode 属性 East_Asian_Width 的值为 Fullwidth (F) 或 Wide (W)
  • U+4DC0 - U+4DFF (易经卦象)
  • U+1F300 – U+1F5FF (各种符号和象形文字)
  • U+1F900 – U+1F9FF (补充符号和象形文字)
assert(std::format("{:.^5s}",   "🐱")    == ".🐱..");
assert(std::format("{:.5s}",    "🐱🐱🐱") == "🐱🐱");
assert(std::format("{:.<5.5s}", "🐱🐱🐱") == "🐱🐱.");

[编辑] L (特定于区域设置的格式)

L 选项会导致使用特定于区域设置的格式。此选项仅对算术类型有效。

  • 对于整数类型,特定于区域设置的格式会根据上下文的区域设置插入适当的数字组分隔符字符。
  • 对于浮点类型,特定于区域设置的格式会根据上下文的区域设置插入适当的数字组和基数分隔符字符。
  • 对于 bool 的文本表示,特定于区域设置的格式会使用适当的字符串,就好像使用 std::numpunct::truenamestd::numpunct::falsename 获得的字符串一样。

[编辑] 类型

type 选项确定数据应该如何呈现。

可用的字符串呈现类型为

  • 无,s: 将字符串复制到输出。
  • ?: 将转义字符串 (参见 下文) 复制到输出。
(从 C++23 起)

charwchar_tbool 之外的整数类型的可用整数呈现类型为

  • b: 二进制格式。生成输出,就好像通过调用 std::to_chars(first, last, value, 2) 一样。基数前缀为 0b
  • B: 与 b 相同,只是基数前缀为 0B
  • c: 将字符 static_cast<CharT>(value) 复制到输出,其中 CharT 是格式字符串的字符类型。如果 value 不在 CharT 的可表示值的范围内,则抛出 std::format_error
  • d: 十进制格式。生成输出,就好像通过调用 std::to_chars(first, last, value) 一样。
  • o: 八进制格式。生成输出,就好像通过调用 std::to_chars(first, last, value, 8) 一样。如果相应的参数值为非零,则基数前缀为 0,否则为空。
  • x: 十六进制格式。生成输出,就好像通过调用 std::to_chars(first, last, value, 16) 一样。基数前缀为 0x
  • X: 与 x 相同,只是它使用大写字母表示大于 9 的数字,基数前缀为 0X
  • 无: 与 d 相同。

可用的 charwchar_t 呈现类型为

  • 无,c: 将字符复制到输出。
  • bBdoxX: 使用整数呈现类型,其值为 static_cast<unsigned char>(value)static_cast<std::make_unsigned_t<wchar_t>>(value),分别。
  • ?: 将转义字符 (参见 下文) 复制到输出。
(从 C++23 起)

可用的 bool 呈现类型为

  • 无,s: 将文本表示 (truefalse,或特定于区域设置的格式) 复制到输出。
  • bBdoxX: 使用整数呈现类型,其值为 static_cast<unsigned char>(value)

可用的浮点呈现类型为

  • a: 如果指定了 precision,则生成输出,就好像通过调用 std::to_chars(first, last, value, std::chars_format::hex, precision) 一样,其中 precision 是指定的精度;否则,生成输出,就好像通过调用 std::to_chars(first, last, value, std::chars_format::hex) 一样。
  • A: 与 a 相同,只是它使用大写字母表示大于 9 的数字,并使用 P 表示指数。
  • e: 生成输出,就好像通过调用 std::to_chars(first, last, value, std::chars_format::scientific, precision) 一样,其中 precision 是指定的精度,或者如果未指定精度,则为 6。
  • E: 与 e 相同,只是它使用 E 表示指数。
  • fF: 生成输出,就好像通过调用 std::to_chars(first, last, value, std::chars_format::fixed, precision) 一样,其中 precision 是指定的精度,或者如果未指定精度,则为 6。
  • g: 生成输出,就好像通过调用 std::to_chars(first, last, value, std::chars_format::general, precision) 一样,其中 precision 是指定的精度,或者如果未指定精度,则为 6。
  • G: 与 g 相同,只是它使用 E 表示指数。
  • 无: 如果指定了 precision,则生成输出,就好像通过调用 std::to_chars(first, last, value, std::chars_format::general, precision) 一样,其中 precision 是指定的精度;否则,生成输出,就好像通过调用 std::to_chars(first, last, value) 一样。

对于小写呈现类型,无穷大和 NaN 分别格式化为 infnan。对于大写呈现类型,无穷大和 NaN 分别格式化为 INFNAN

可用的指针呈现类型 (也用于 std::nullptr_t) 为

  • 无,p: 如果定义了 std::uintptr_t,则生成输出,就好像通过调用 std::to_chars(first, last, reinterpret_cast<std::uintptr_t>(value), 16) 一样,并向输出添加前缀 0x;否则,输出由实现定义。
  • P: 与 p 相同,只是它使用大写字母表示大于 9 的数字,基数前缀为 0X
(从 C++26 起)


格式化转义字符和字符串

可以将字符或字符串格式化为 转义,使其更适合调试或记录。

转义的执行方式如下

  • 对于每个对字符 C 进行编码的格式良好的代码单元序列
  • 如果 C 是下表中的一个字符,则使用相应的转义序列。
字符 转义序列 备注
水平制表符 (ASCII 编码中的字节 0x09) \t
换行符 - 换行 (ASCII 编码中的字节 0x0a) \n
回车符 (ASCII 编码中的字节 0x0d) \r
双引号 (ASCII 编码中的字节 0x22) \" 仅在输出为双引号字符串时使用
单引号 (ASCII 编码中的字节 0x27) \' 仅在输出为单引号字符串时使用
反斜杠 (ASCII 编码中的字节 0x5c) \\
  • 否则,如果 C 不是空格字符 (ASCII 编码中的字节 0x20),并且
  • 关联的字符编码是 Unicode 编码,并且
  • C 对应于 Unicode 标量值,其 Unicode 属性 General_Category 的值属于 Separator (Z) 或 Other (C) 组,或者
  • C 没有紧接在非转义字符之前,并且 C 对应于具有 Unicode 属性 Grapheme_Extend=Yes 的 Unicode 标量值,或者
  • 关联的字符编码不是 Unicode 编码,并且 C 是实现定义的分隔符或不可打印字符集之一
转义序列为 \u{hex-digit-sequence},其中 hex-digit-sequence 是使用小写十六进制数字表示的 C 的最短十六进制表示。
  • 否则,C 按原样复制。
  • 作为移位序列的代码单元序列对字符串的输出和进一步解码具有未指定的影响。
  • 其他代码单元(即那些在格式错误的代码单元序列中的代码单元)分别被替换为 \x{hex-digit-sequence},其中 hex-digit-sequence 是使用小写十六进制数字表示的代码单元的最短十六进制表示。

字符串的转义字符串表示是通过转义字符串中的代码单元序列(如上所述)并用双引号引起来构建的。

字符的转义表示是通过如上所述对其进行转义并用单引号引起来构建的。

编译器资源管理器演示

#include <print>
 
int main()
{
    std::println("[{:?}]", "h\tllo");             // prints: ["h\tllo"]
    std::println("[{:?}]", "Спасибо, Виктор ♥!"); // prints: ["Спасибо, Виктор ♥!"]
    std::println("[{:?}] [{:?}]", '\'', '"');     // prints: ['\'', '"']
 
    // The following examples assume use of the UTF-8 encoding
    std::println("[{:?}]", std::string("\0 \n \t \x02 \x1b", 9));
                                             // prints: ["\u{0} \n \t \u{2} \u{1b}"]
    std::println("[{:?}]", "\xc3\x28");      // invalid UTF-8
                                             // prints: ["\x{c3}("]
    std::println("[{:?}]", "\u0301");        // prints: ["\u{301}"]
    std::println("[{:?}]", "\\\u0301");      // prints: ["\\\u{301}"]
    std::println("[{:?}]", "e\u0301\u0323"); // prints: ["ẹ́"]
}
(从 C++23 起)

[编辑] 注释

在大多数情况下,语法类似于旧的 % 格式化,但添加了 {},并使用 : 代替 %。例如,"%03.2f" 可以转换为 "{:03.2f}".

特性测试 Std 特性
__cpp_lib_format_uchar 202311L (C++20)
(DR)
代码单元的格式化为无符号整数

[编辑] 缺陷报告

以下更改行为的缺陷报告被追溯应用于以前发布的 C++ 标准。

DR 应用于 发布的行为 正确行为
LWG 3721 C++20 宽度字段不允许为零
在标准格式规范中
如果通过替换字段指定,则允许为零
P2909R4 C++20 charwchar_t 可能被格式化为
超出范围的无符号整数值
代码单元在进行此类格式化之前被转换为相应的
无符号类型