C语言格式化输出
介绍
格式化输出函数会根据参数 format 字符串来转换并格式化数据,然后输出。其中字符串由多个指令组成。指令有以下两种:
- 非 % 字符,将会被原封不动的拷贝到输出流
- 由 % 字符开头的转换说明符号,每个都会从后面取出若干个参数,按照相应的转换规则(如果适用)转换并将结果写入输出流
一般而言,每个 % 符号在其后都必需有一个参数与之相呼应(只有当 %% 转换字符出现时会直接输出 % 字符),而欲输出的数据类型必须与其相对应的转换字符类型相同。
组成规则
格式化说明符的组成规则如下:
'%' [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