- 调试输出
- LCD显示内容
格式化输出函数printf、fprintf、sprintf和snprintf在格式化处理部分是相同的,本文以printf为例,说明此类函数的用法。
printf函数的调用格式为:
printf(“<格式化字符串>”, <参量表>);
比如:
printf("The Value %d.n", 500); //输出数字
这句代码产生如下输出:
格式化字符串The value 500.
在上面提到的 printf 函数调用格式 printf("<格式化字符串>", <参量表>); 中,我们忽略其中的**<参量表>,只关注"<格式化字符串>"**。
"<格式化字符串>"应该是一个字符序列,形如:
转换说明“普通字符(%除外) %<转换参数> …”
在形如 “普通字符(% 除外) %<转换参数> ...” 的格式化字符串中,普通字符(%除外)原封不动的被复制到输出流,以%开头的转换说明用于指示转换数据类型、精度等,转换说明的格式为:
转换参数% <标志字符> <最小字段宽度> <精度说明>
<转换类型字符>
在转换说明中,<标志字符> <最小字段宽度> <精度说明>
printf("The Value %d.n", 500); //输出数字
%d是一个转换说明,它只有一个转换参数:d。转换参数 d 属于 5 种转换参数中的转换类型字符。这个是我们接触最早也最多的转换参数。
小结我们一步一步的忽略 printf 函数的次要内容,只关心其中的转换说明,这一过程可以用一张图来表示:
下面详细描述5种转换参数。
标志字符允许0个或多个标志字符,如果标志字符多于1个,它们的顺序任意。标志字符有:
-
- :左对齐字段宽度中的值。没有这个标志字符,则是右对齐。比较代码:
int value = 500; printf("The value |%-8d|n", value); //左对齐 printf("The value |%8d|n", value); //右对齐代码输出:
The value |500 | The value | 500|
-
+ :有符号数转换总是显示符号:正号(+)或负号(-)。如果没有这个标志字符,只有负值才会显示符号。比较代码:
printf("The value %dn", 500); //正数无 '+' printf("The value %dn", -500); //负数无 '+' printf("The value %+dn", 500); //正数有 '+'代码输出:
The value 500 The value -500 The value +500
-
空格 :有符号数转换的结果中第一个字符不是符号(比如默认情况下转换正数是不显示正号(+)的),则在结果前加一个空格。如果同时出现 空格 和 + 标志字符,则忽略 空格 标志。
这个标志可以实现有符号数的数字域对齐,在LCD显示数据时很有用,比较代码:
printf("The value % dn", 500); //有'空格'标志 printf("The value % dn", -500); //有'空格'标志 printf("The value %+ dn", 500); //同时有'空格'和'+'标志代码输出:
The value 500 The value -500 The value +500
-
# :对于 o、x、X 转换类型,在非零结果前添加前缀,比如十六进制前缀 0x ,比较代码:
printf("The value %on", 0500); //八进制,无'#'标志 printf("The value %#on", 0500); //八进制,有'#'标志 printf("The value %#on", 0); //八进制,有'#'标志 printf("The value %xn", 0x500); //十六进制,无'#'标志 printf("The value %#xn", 0x500); //十六进制,有'#'标志 printf("The value %#xn", 0); //十六进制,有'#'标志代码输出:
The value 500 The value 0500 The value 0 The value 500 The value 0x500 The value 0
浮点数
对于 e、E、f、g、G 转换类型,即使小数点后面没有数,结果也要包含一个小数点。比较代码(这里会用到精度说明参数,可以在理解了精度说明参数后再看这个例子):
printf("The value %.0fn", 500.1234); //精度指定为0 printf("The value %#.0fn", 500.1234); //精度指定为0,有'#'标志代码输出:
The value 500 The value 500.
-
0 :使用 0 填充,没有这个标志字符,则使用 空格 填充,如果和左对齐标志(-)同时出现,则忽略0填充标志(0)。比较代码:
int value = 500; printf("The value |%8d|n", value); //空格填充,右对齐 printf("The value |%08d|n", value); // 0填充,右对齐 printf("The value |%-8d|n", value); //空格填充,左对齐 printf("The value |%-08d|n", value); //左对齐标志('-')和0填充标志('0')同时出现,忽略0填充标志代码输出:
The value | 500| The value |00000500| The value |500 | The value |500 |
可选。
最小字段宽度是一个 * 或者是一个十进制整数。如果转换结果比最小字段宽度小,则转换结果会被填充。
-
左对齐标志举例 printf("The value |%8d|n", value); ,其中 %8d 中的十进制整数 8 就是最小字段宽度,比较代码:
printf("The value |%8d|n", 500); //空格填充,右对齐 printf("The value |%08d|n", 500); // 0填充,右对齐 printf("The value |%8d|n", 1234567890); //空格填充,右对齐,数值大于最小字段宽度 printf("The value |%08d|n", 1234567890); // 0填充,右对齐,数值大于最小字段宽度代码输出:
The value | 500| The value |00000500| The value |1234567890| The value |1234567890|
-
如果最小字段宽度是一个 * ,一个int型参数提供最小字段宽度。比较代码:
printf("The value |%*d|n", 8, 500); //空格填充,右对齐,使用'*' printf("The value |%0*d|n", 8, 500); // 0填充,右对齐,使用'*' printf("The value |%8d|n", 500); //空格填充,右对齐 printf("The value |%08d|n", 500); // 0填充,右对齐代码输出:
The value | 500| The value |00000500| The value | 500| The value |00000500|
可选。
精度说明是小数点 . 后跟一个 * 或者是一个十进制整数。
-
与最小字段宽度类似,如果精度说明是 .* ,一个int型参数提供精度。
-
对于 d、i、o、x、X 转换类型,精度说明指定了转换中出现数字的最少个数。比较代码:
printf("The value |%8d|n", 500); //空格填充,右对齐 printf("The value |%.8d|n", 500); //使用精度说明,对空格填充有影响 printf("The value |%.8d|n", 1234567890); //使用精度说明,数值大于指定精度代码输出:
The value | 500| The value |00000500| The value |1234567890|
-
对于 e、E、f 转换类型,精度说明指定了转换的小数点右边的个数。比较代码:
printf("The value %fn", 500.1234); //不使用精度说明 printf("The value %.2fn", 500.1234); //使用精度说明 printf("The value %en", 500.1234); //不使用精度说明 printf("The value %.2en", 500.1234); //使用精度说明代码输出:
The value 500.123400 The value 500.12 The value 5.001234e+02 The value 5.00e+02 -
对于 s 转换类型,精度说明指定了转换中要从字符串写入的最大字符数。比较代码:
char *string = "123456789"; printf("The value %sn", string); //不使用精度说明 printf("The value %.2sn", string); //使用精度说明代码输出:
The value 123456789 The value 12
CmBacktrace 源码在输出最后字符串时使用了这个特性(%.*s),在格式化时可以避免处理字符串结尾符。如代码所示:
cmb_println("查看更多函数调用栈信息,请运行:addr2line -e %s%s -a -f %.*s", fw_name, CMB_ELF_FILE_EXTENSION_NAME, cur_depth * (8 + 1), call_stack_info);
h、l、LCmBacktrace (Cortex Microcontroller Backtrace)是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位,错误原因自动分析的开源库。
可选。
- h 表示转换参数的类型为 short int 或 unsigned short int ,只对 d、i、o、x、X 转换类型有效;
- l 表示转换参数的类型为 long int 或 unsigned long int ,只对 d、i、o、x、X 转换类型有效;
- L 表示转换参数的类型为 long double ,只对e、E、f、g、G 转换类型有效。
-
d、i :将 int 参数转换为有符号十进制数;
-
o :将 unsigned int 参数转换为无符号八进制数;
-
u :将 unsigned int 参数转换为无符号十进制数;
-
x、X :将 unsigned int 参数转换为无符号十六进制数;
-
f :将 double 参数转换为十进制数,形式为 [-]ddd.ddd ,默认精度为6位;
-
e、E :将 double 参数转换为十进制数,形式为 [-]d.ddde±dd ,默认精度为6位;
-
c :将 int 参数转换为 unsigned char 类型,并输出结果;
-
s :参数应该是指向字符型数组的指针,如果指定了精度说明,则最多转换精度说明指定的字符,否则,数组应包含一个字符串结尾符。
-
p :参数是一个指向 void 类型的指针;
-
n :参数是一个指向整形变量的指针,这个整形变量记录到目前为止通过调用 printf 所转换的字符总数。不转换参数。
int num1, num2; printf("The value %n%s%nn", &num1, string, &num2); printf("num1 = %dn", num1); printf("num2 = %dn", num2);代码输出:
The value 123456789 num1 = 10 num2 = 19
-
% :转换一个 % 号。
用一张图来表示以上内容:
参考:《C标准库》



