printf 日常使用指南
Posted 研究是为了理解
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了printf 日常使用指南相关的知识,希望对你有一定的参考价值。
格式化适用场景
- 调试输出
- LCD显示内容
格式化函数的一般格式
格式化输出函数printf
、fprintf
、sprintf
和snprintf
在格式化处理部分是相同的,本文以printf
为例,说明此类函数的用法。
printf
函数的调用格式为:
printf(“<格式化字符串>”, <参量表>);
比如:
printf("The Value %d.\\n", 500); //输出数字
这句代码产生如下输出:
The value 500.
格式化字符串
在上面提到的 printf
函数调用格式 printf("<格式化字符串>", <参量表>);
中,我们忽略其中的 <参量表>,只关注 <格式化字符串>。
"<格式化字符串>"应该是一个字符序列,形如:
“普通字符(%除外) %<转换参数> …”
转换说明
在形如 “普通字符(% 除外) %<转换参数> ...”
的格式化字符串中,普通字符(%除外)原封不动的被复制到输出流,以%
开头的转换说明用于指示转换数据类型、精度等,转换说明的格式为:
% <标志字符> <最小字段宽度> <精度说明> <h、l、L> <转换类型字符>
转换参数
在转换说明中,<标志字符> <最小字段宽度> <精度说明> <h、l、L> <转换类型字符>
统称为转换参数,一共有5种转换参数。除 <转换类型字符>
外,其它4种都可以忽略不用。我们再看一下上文的例子:
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 %d\\n", 500); //正数无 '+' printf("The value %d\\n", -500); //负数无 '+' printf("The value %+d\\n", 500); //正数有 '+'
代码输出:
The value 500 The value -500 The value +500
-
空格
:有符号数转换的结果中第一个字符不是符号(比如默认情况下转换正数是不显示正号(+)
的),则在结果前加一个空格。如果同时出现空格
和+
标志字符,则忽略空格
标志。这个标志可以实现有符号数的数字域对齐,在LCD显示数据时很有用,比较代码:
printf("The value % d\\n", 500); //有'空格'标志 printf("The value % d\\n", -500); //有'空格'标志 printf("The value %+ d\\n", 500); //同时有'空格'和'+'标志
代码输出:
The value 500 The value -500 The value +500
-
#
:对于o、x、X
转换类型,在非零结果前添加前缀,比如十六进制前缀0x
,比较代码:printf("The value %o\\n", 0500); //八进制,无'#'标志 printf("The value %#o\\n", 0500); //八进制,有'#'标志 printf("The value %#o\\n", 0); //八进制,有'#'标志 printf("The value %x\\n", 0x500); //十六进制,无'#'标志 printf("The value %#x\\n", 0x500); //十六进制,有'#'标志 printf("The value %#x\\n", 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 %.0f\\n", 500.1234); //精度指定为0 printf("The value %#.0f\\n", 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 %f\\n", 500.1234); //不使用精度说明 printf("The value %.2f\\n", 500.1234); //使用精度说明 printf("The value %e\\n", 500.1234); //不使用精度说明 printf("The value %.2e\\n", 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 %s\\n", string); //不使用精度说明 printf("The value %.2s\\n", 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);
CmBacktrace (Cortex Microcontroller Backtrace)是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位,错误原因自动分析的开源库。
h、l、L
可选。
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%n\\n", &num1, string, &num2); printf("num1 = %d\\n", num1); printf("num2 = %d\\n", num2);
代码输出:
The value 123456789 num1 = 10 num2 = 19
-
%
:转换一个%
号。
最后的总结
用一张图来表示以上内容:
参考:《C标准库》
读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
以上是关于printf 日常使用指南的主要内容,如果未能解决你的问题,请参考以下文章