介绍

格式化输出函数会根据参数 format 字符串来转换并格式化数据,然后输出。其中字符串由多个指令组成。指令有以下两种:

  1. 非 % 字符,将会被原封不动的拷贝到输出流
  2. 由 % 字符开头的转换说明符号,每个都会从后面取出若干个参数,按照相应的转换规则(如果适用)转换并将结果写入输出流

一般而言,每个 % 符号在其后都必需有一个参数与之相呼应(只有当 %% 转换字符出现时会直接输出 % 字符),而欲输出的数据类型必须与其相对应的转换字符类型相同。

组成规则

格式化说明符的组成规则如下:

'%' [flags]zero-or-more [field-width]opt [precision]opt [length-modifier]opt conversition-specifier
  • flags: 任意个数,用来修改转换说明符的行为
  • field-width: 可选,如果转换后的值的字符数少于字段宽度,则在左侧用空格填充剩余字段(默认情况下为左)。字段宽度采用星号*(稍后描述)或非负十进制整数的表示。
  • precision: 可选,参考 precision
  • length-modifer: 可选,用于指定输入参数的长度
  • conversition-specifier: 字符,说明用什么转换类型来转换参数

flags

flag 字符可以按照任意的次序写,所有的 flag 字符和它们的含义如下:

- 返回的结果为左对齐,默认情况为右对齐

+ 有符号的转换结果前始终包括加号或者减号(默认情况下只有负数前才会显示一个符号)

space 如果有符号的转换的结果第一个字符不是符号,或者如果有符号的转换结果没有字符,都会在前面加上一个空格。如果空格和 + 两个 flag 都出现,则忽略空格。

# 将结果转换为“替代形式”。对于 o 转换,当且仅当必要时,它会提高精度,以将结果的第一位数强制设为零(如果值和精度均为 0 ,则打印单个 0 )。对于x(或 X )转换,非零结果前将加上 0x(或 0X)前缀。 对于 a,e,E,f,F,g 和 G 转换,转换的结果总是包含一个小数点字符,即使小数点后没有数字(正常情况下只有后面有数字是才会出现小数点)。对于 g 和 G 转换,尾随零并不会从结果中移除。对于其他转换,行为是未定义的。

0 对于 d,i,o,u,x,x,a,A,e,E,f,F,g 和 G 转换,除非转换无效或者 NaN,使用前导零填充剩余宽度字符(在 +- 和 0x 的基础上)。如果同时出现 0 和 -,则 0 被忽略。对于其他转换,行为是未定义的。

precision(精度)

precision 有几种情况:

  • 给出 d,i,o,u,x 和 X 转换所显示的最小位数
  • 给出 a,e,E,f 和 F 转换的小数点后出现的位数
  • g 和 G 格式代表有效位数的最大值
  • 在 %s 格式代表字符串的最大长度

Notice: 如果精度和非上述类型说明符(conversition specifier)一起使用,行为是未定义的。

精度由 . (period) 开头,比如 .3d,后面加上 * 号或可选的十进制整数(如果仅仅只有一个.,那么精度为0)。

如上所述,字段宽度(field-width)或精度(precision)两者都可以用星号表示。在这种情况下,表示用一个 int 类型的参数提供字段的宽度或精度。指定字段宽度或精度或两者的参数将在要转换的参数(如果有的话)之前出现(按顺序)。

如果字段宽度为负数,相当于一个 - flag 加上正的字段宽度;如果精度为负数,那么会被忽略。

length modifier

hh 表示紧跟着的 d, i, o, u, x 或者 X 转换说明符将被应用到 signed char 或者 unsigned char 参数(参数已经通过整数提升提升了,但是它的值仍然应该被转换为对应的类型);如果紧跟 n 说明符则表示参数应该是指向 signed char 类型的指针。

h 表示紧跟着的 d, i, o, u, x 或者 X 转换说明符将被应用到 short int 或者 unsigned short int 参数(参数已经通过整数提升提升了,但是它的值仍然应该被转换为对应的类型);如果紧跟 n 说明符则表示参数应该是指向 short int 类型的指针。

l(ell) 表示紧跟着的 d, i, o, u, x 或者 X 转换说明符将被应用到 long int 或者 unsigned long int 参数;如果紧跟 n 说明符则表示参数应该是指向 long int 类型的指针;如果紧跟着 c 说明符则表示 wint_t 参数;如果紧跟着 s 则表示参数为 wchar_t 类型的指针;对于 a, A, e, E, f, F, g 和 G 则没有任何影响。

ll(ell-ell) 表示紧跟着的 d, i, o, u, x 或者 X 转换说明符将被应用到 long long int 或者 unsigned long long int 参数;如果紧跟 n 说明符则表示参数应该是指向 long long int 类型的指针。

j 表示紧跟着的 d, i, o, u, x 或者 X 转换说明符将被应用到 intmax_t 或者 uintmax_t 参数;如果紧跟 n 说明符则表示参数应该是指向 intmax_t 类型的指针。

z 表示紧跟着的 d, i, o, u, x 或者 X 转换说明符将被应用到 size_t 或者相应的有符号整形参数;如果紧跟 n 说明符则表示转换规范适用于对应于 size_t 参数的带符号整数类型的指针。

t 表示紧跟着的 d, i, o, u, x 或者 X 转换说明符将被应用到 ptrdiff_t 或者相应的无符号整形参数;如果紧跟 n 说明符则表示参数应该是指向 ptrdiff_t 类型的指针。

L 表示紧跟着的 a, A, e, E, f, F, g 或者 G 转换说明符将被应用到 long double 类型的参数上。

conversition-specifier

整数

  • %d,i 整数的参数会被转成有符号的十进制数字。
  • %u 整数的参数会被转成无符号的十进制数字。
  • %o 整数的参数会被转成无符号的八进制数字。
  • %x,X 整数的参数会被转成无符号的十六进制数字,并以小写abcdef 表示,对于 X 以大写ABCDEF 表示浮点型数(下同,不在赘述)。
  • %f,F double 型的参数会被转成十进制数字 [-]ddd.ddd,并取到小数点以下六位,四舍五入。如果为无穷(infinity)则按照具体实现输出 [-]inf 或者 infinity;如果为 NaN 则输出 [-]nan 或者 [-]nan(any n-char-sequence)
  • %e,E double 型的参数以指数形式打印,有一个数字会在小数点前,六位数字在小数点后,而在指数部分会以小写的 e 来表示[-]d.ddde+/-dd。如果参数表示无穷(infinity)或者 NaN 则类似于 f 或 F。
  • %g,G double 型的参数会自动选择以 %f 或 %e 的格式来打印,其标准是根据打印的数值及所设置的有效位数来决定。
  • %a, A 浮点数、十六进制数字和p-记数法。把一个浮点数以一个十六进制的数如0x1.C0000p+1类似的样子输出一个浮点数。

字符及字符串

  • %c 整型数的参数会被转成 unsigned char 型打印出
  • %s 指向字符串的参数会被逐字输出,直到出现 '\0' 字符为止
  • %p 如果是参数是 void * 型指针则使用十六进制格式显示

others

最后,标准规定:

The number of characters that can be produced by any single conversion shall be at least 4095.

references

[1] ISO/IEC 9899:201x Committee Draft — December 2, 2010 N1548