1. 格式化字符串定义
格式化字符串,是一些程序设计语言在格式化输出API函数中用于指定输出参数的格式与相对位置的字符串参数,例如C、C++等程序设计语言的printf类函数,其中的转换说明(conversion specification)用于把随后对应的0个或多个函数参数转换为相应的格式输出;格式化字符串中转换说明以外的其它字符原样输出。
2. POSIX标准下的printf函数
2.1 格式化占位符
格式化字符串中的占位符用于指明输出的参数值如何格式化。
格式化占位符(format placeholder),语法是:
%[parameter][flags][field width][.precision][length]type
Parameter可以忽略或者是:
字符 | 描述 |
---|---|
n$ | n是用这个格式说明符(specifier)显示第几个参数;这使得参数可以输出多次,使用多个格式说明符,以不同的顺序输出。 如果任意一个占位符使用了parameter,则其他所有占位符必须也使用parameter。这是POSIX扩展,不属于ISO C。例:printf("%2$d %2$#x; %1$d %1$#x",16,17) 产生"17 0x11; 16 0x10" |
Flags可为0个或多个:
字符 | 描述 |
---|---|
+ | 总是表示有符号数值的'+'或'-'号,缺省情况是忽略正数的符号。仅适用于数值类型。 |
空格 | 使得有符号数的输出如果没有正负号或者输出0个字符,则前缀1个空格。如果空格与'+'同时出现,则空格说明符被忽略。 |
- | 左对齐。缺省情况是右对齐。 |
# | 对于'g'与'G',不删除尾部0以表示精度。对于'f', 'F', 'e', 'E', 'g', 'G', 总是输出小数点。对于'o', 'x', 'X', 在非0数值前分别输出前缀0, 0x, and 0X表示数制。 |
0 | 如果width选项前缀以0,则在左侧用0填充直至达到宽度要求。例如printf("%2d", 3)输出" 3",而printf("%02d", 3)输出"03"。如果0与-均出现,则0被忽略,即左对齐依然用空格填充。 |
Field Width给出显示数值的最小宽度,典型用于制表输出时填充固定宽度的表目。实际输出字符的个数不足域宽,则根据左对齐或右对齐进行填充。实际输出字符的个数超过域宽并不引起数值截断,而是显示全部。宽度值的前导0被解释为0填充标志,如上述;前导的负值被解释为其绝对值,负号解释为左对齐标志。如果域宽值为*
,则由对应的函数参数的值为当前域宽。
Precision通常指明输出的最大长度,依赖于特定的格式化类型。对于d、i、u、x、o的整型数值,是指最小数字位数,不足的位要在左侧补0,如果超过也不截断,缺省值为1。对于a,A,e,E,f,F的浮点数值,是指小数点右边显示的数字位数,必要时四舍五入;缺省值为6。对于g,G的浮点数值,是指有效数字的最大位数。对于s的字符串类型,是指输出的字节的上限,超出限制的其它字符将被截断。如果域宽为*
,则由对应的函数参数的值为当前域宽。如果仅给出了小数点,则域宽为0。
Length指出浮点型参数或整型参数的长度。此项Microsoft称为“Size”。可以忽略,或者是下述:
字符 | 描述 |
---|---|
hh | 对于整数类型,printf期待一个从char提升的int尺寸的整型参数。 |
h | 对于整数类型,printf期待一个从short提升的int尺寸的整型参数。 |
l | 对于整数类型,printf期待一个long尺寸的整型参数。 对于浮点类型,printf期待一个double尺寸的整型参数。 对于字符串s类型,printf期待一个wchar_t指针参数。 对于字符c类型,printf期待一个wint_t型的参数。 |
ll | 对于整数类型,printf期待一个long long尺寸的整型参数。Microsoft也可以使用I64 |
L | 对于浮点类型,printf期待一个long double尺寸的整型参数。 |
z | 对于整数类型,printf期待一个size_t尺寸的整型参数。 |
j | 对于整数类型,printf期待一个intmax_t尺寸的整型参数。 |
t | 对于整数类型,printf期待一个ptrdiff_t尺寸的整型参数。 |
此外,在ISO C99广泛接受前,还有几个平台相关的length选项:
字符 | 描述 |
---|---|
I | 对于有符号整数类型,printf期待一个ptrdiff_t尺寸的整型参数。对于无符号整数类型,printf期待一个size_t尺寸的整型参数。常见于Win32/Win64平台。 |
I32 | 对于整数类型,printf期待一个32位(双字)的整型参数。常见于Win32/Win64平台。 |
I64 | 对于整数类型,printf期待一个64位(四字)的整型参数。常见于Win32/Win64平台。 |
q | 对于整数类型,printf期待一个64位(四字)的整型参数。常见于BSD平台。 |
ISO C99的头文件inttypes.h
包含了许多宏,用于平台独立的printf
编码。例如:
2.2 类型
Type,也称转换说明(conversion specification/specifier),可以是:
字符 | 描述 |
---|---|
d,i | 有符号十进制数值int。'%d'与'%i'对于输出是同义;但对于scanf()输入二者不同,其中%i在输入值有前缀0x或0时,分别表示16进制或8进制的值。如果指定了精度,则输出的数字不足时在左侧补0。默认精度为1。精度为0且值为0,则输出为空。 |
u | 十进制unsigned int。如果指定了精度,则输出的数字不足时在左侧补0。默认精度为1。精度为0且值为0,则输出为空。 |
f,F | double型输出10进制定点表示。'f'与'F'差异是表示无穷与NaN时,'f'输出'inf', 'infinity'与'nan';'F'输出'INF', 'INFINITY'与'NAN'。小数点后的数字位数等于精度,最后一位数字四舍五入。精度默认为6。如果精度为0且没有#标记,则不出现小数点。小数点左侧至少一位数字。 |
e,E | double值,输出形式为10进制的([-]d.ddd e[+/-]ddd). E版本使用的指数符号为E(而不是e)。指数部分至少包含2位数字,如果值为0,则指数部分为00。Windows系统,指数部分至少为3位数字,例如1.5e002,也可用Microsoft版的运行时函数_set_output_format 修改。小数点前存在1位数字。小数点后的数字位数等于精度。精度默认为6。如果精度为0且没有#标记,则不出现小数点。 |
g,G | double型数值,精度定义为全部有效数字位数。当指数部分在闭区间 [-4,精度] 内,输出为定点形式;否则输出为指数浮点形式。'g'使用小写字母,'G'使用大写字母。小数点右侧的尾数0不被显示;显示小数点仅当输出的小数部分不为0。 |
x,X | 16进制unsigned int。'x'使用小写字母;'X'使用大写字母。如果指定了精度,则输出的数字不足时在左侧补0。默认精度为1。精度为0且值为0,则输出为空。 |
o | 8进制unsigned int。如果指定了精度,则输出的数字不足时在左侧补0。默认精度为1。精度为0且值为0,则输出为空。 |
s | 如果没有用l标志,输出null结尾字符串直到精度规定的上限;如果没有指定精度,则输出所有字节。如果用了l标志,则对应函数参数指向wchar_t型的数组,输出时把每个宽字符转化为多字节字符,相当于调用wcrtomb函数。 |
c | 如果没有用l标志,把int参数转为unsigned char型输出;如果用了l标志,把wint_t参数转为包含两个元素的wchart_t数组,其中第一个元素包含要输出的字符,第二个元素为null宽字符。 |
p | void *型 |
a,A | double型的16进制表示,"[−]0xh.hhhh p±d"。其中指数部分为10进制表示的形式。例如:1025.010输出为0x1.004000p+10。'a'使用小写字母,'A'使用大写字母。(C++11流使用hexfloat输出16进制浮点数) |
n | 不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。 |
% | '%'字面值,不接受任何flags, width, precision or length。 |
宽度与精度格式化参数可以忽略,或者直接指定,或者用星号"*
"表示取对应函数参数的值。例如printf("%*d", 5, 10)
输出"10
";printf("%.*s", 3, "abcdef")
输出"abc
"。
某些编译器,如GCC,会静态检查printf这一类函数的格式化参数并编译警告存在的问题(当使用编译标志-Wall
或-Wformat
)。GCC也会对用户自定义的printf风格函数做静态检查,如果在函数定义时使用了非标准的"format
" __attribute__
。
3. 格式化字符串函数
输入
- scanf
输出
| 函数 | 基本介绍 |
| ------------------------ | -------------------------------------- |
| printf | 输出到stdout |
| fprintf | 输出到指定FILE流 |
| vprintf | 根据参数列表格式化输出到 stdout |
| vfprintf | 根据参数列表格式化输出到指定FILE流 |
| sprintf | 输出到字符串 |
| snprintf | 输出指定字节数到字符串 |
| vsprintf | 根据参数列表格式化输出到字符串 |
| vsnprintf | 根据参数列表格式化输出指定字节到字符串 |
| setproctitle | 设置argv |
| syslog | 输出日志 |
| err, verr, warn, vwarn等 | 。。。 |
其实不止printf函数可以格式化字符串,printf函数的变形也可以,例如printf_chk
printf_chk和printf不同的地方有两点:
- 不能使用$n不连续的打印
- 在使用%n的时候会做一系列检查