先看例子:
printf("This line has only controlling strings.\n");
`printf(“I am %d years old and %f inch tall”, 21, 132);
参数
printf()的参数分为两大部分,分别是控制字符串和参数列表,二者用逗号隔开,而且参数之间也要用逗号隔开。其中控制字符串是字符串常量,如果不需要其他参数的话,双引号里面的文字将被原原本本的打印到屏幕。通俗的讲,双引号里面是什么,输出的就是什么,包括转义字符。
但是,这样以来,我们无论想要打印什么,都只能手动的写在双引号内部,从而无法实现自动化打印。比如,怎样输出程序中变量的值?总不能变量的值变一次我们就手动改写一次printf()函数吧?那就违背了写程序的初衷。
所以必须要有一种办法让函数能打印变量的值,然而,把变量名称直接写进双引号内部是不可行的,因为这时变量名就成了字符串常量的一部分——双引号的内部的字符将被视为普通文本。
于是,在控制字符串中引入了一个特殊字符’%’,这个字符和后面的某些字符组合起来会转义,即不会再被视为普通文本,而是有其他用途。比如上面例子中的%d,它表示这个位置要打印的是一个十进制数字而不是%d本身,实际的数值由字符串后面对应的变量或常量提供。%被称为占位符,表示先占住一个固定的位置,然后再往里面添加内容;d是格式说明符,表明以哪种格式打印对应的参数。%d合称为格式占位符或转换说明符。
可以看出,参数可以是变量也可以是常量,还可以是表达式。但是要注意的是,参数必须和控制字符串中转换说明符的个数匹配且顺序一致;还有,每个参数的类型要和对应的转换说明符匹配,比如浮点数就不应该用%d打印。下面详谈各种转换说明符的使用。
转换说明符
上面所说的格式转换到底是啥意思呢?我们要知道,任何数据在计算机中都是以二进制的形式存储的,变量或常量对应的那块存储空间存放的可能是一串二进制数字:01000001,那么把它理解为一个十六进制数字或者说以十六进制的形式打印出来就是0x41;以十进制的形式打印出来就是65;以ASCII字符的形式打印出来就是大写字母’A’。* 所以,格式转换的本质就是翻译,把二进制数字翻译成对应的形式。而各种格式说明符就是在指定翻译的规则。*
下面我们逐个介绍这些格式说明符。
整数类型
%d 或 %i :有符号十进制整数,它们的效果是相同的,如下:
printf("this is %d and %i, same.\n", 10, 10);
输出: this is 10 and 10, same.
%u : 无符号十进制整数:
printf("this is %d and %u.\n", -65, -65);
输出:this is -65 and 4294967231.
我们看到,-65这个数以相同的二进制形式存储,但解读的时候发生了变异,原理见前文。
%x 或 %X: 十六进制无符号整数:
printf("this is %d and %x.\n", -65, -65);
printf("this is %d and %X.\n", -65, -65);
输出: this is -65 and ffffffbf.
this is -65 and FFFFFFBF.
%o : 八进制无符号整数:
printf("this is %d and %o.\n", -65, -65);
浮点数类型
%f :十进制记数法的浮点数:
printf("this is %f\n", 12.62543219);
输出:this is 12.625432
可以看出,%f对小数点后面七位以后的数都舍入了,也就是说其精度为6。
%e 或 %E: e或E-记数法的浮点数:
printf("this is %e\n", 0.625);
printf("this is %e\n", 9000876.54);
输出: this is 6.250000e-01
this is 9.000877e+06
可以看出%e或%E只能保留小数点后面六位数。
%g 或 %G :这时,printf把一个浮点数表示为e-记数法,且只保留六位有效数字;然后观察指数,若指数在-4~+5之间时,自动选择%f;反之选择%e或%E(似乎还要复杂,大家自己判断一下吧):
printf("this is %g and %g\n", 0.000089, 0.00089);
printf("this is %G and %G\n", 900876.44, 9000876.44);
输出:this is 8.9e-05 and 0.00089
this is 900876 and 9.00088E+06
%a 或 %A :十六进制的p或P记数法的浮点数(我也不知道这是什么鬼):
printf("this is %a and %A\n", 3.75, -3.75);
输出:this is 0x1.ep+1 and -0X1.EP+1
其他类型
%c :一个字符:
printf("this is %c \n", 66);
输出:this is B %s :字符串:
printf("this is %s \n", "string");
输出:this is string %p:指针:
printf("this is %p \n", "string");
输出:this is 0x8048576 %%:百分号本身,因为单独一个%已经被编译器“征用”了,转义成占位符,所以要打印%本身只好用两个%来代替:
printf("this is %% \n");
输出:this is %
转换说明修饰符
在%和格式说明符之间可以插入各种修饰符来进一步修改最终的打印结果,比如打印的宽度、精度、符号等等。
‘数字’:用来指定打印字段的最小宽度,若该宽度容纳不下结果,则自动超过这个限制而使用更宽的字段:
printf("this is %6d \n", 65);
输出:this is 65
‘.数字’:看配合对象,若是%f等浮点格式说明符,则指定浮点数的精度,即小数点右边打印的数字的位数;对是%s,指定打印字符的最大数目;对整数格式,指定打印数字的最小位数(整数的精度?),不够的话用0做前导填充;若小数点后面没有数字,默认为0,即变成整数:
printf("this is /%.2f/\n", 65.3);
printf("this is /%.f/\n", 65.3);
printf("this is /%.3d/\n", 65);
输出:this is /65.30/
this is /65/
this is /065/
‘-’:减号,用来指定对齐方式,从上面一条结果我们可以看出,默认的对齐方式是右对齐的,而使用了‘-’,就表明要左对齐:
printf("this is /%6d/\n", 65);
printf("this is /%-6d/\n", 65);
输出:this is / 65/
this is /65 /
‘+’ :打印数字的符号,无论数字是正是负。一般情况下只配合有符号格式说明符使用,比如%+d, %+f;但是%+u、%+c等就会报错:
printf("this is %+c \n", 65);
输出:this is +65
‘ ’:这是一个空格,作用和‘+’是相似的,区别就是用空格代替了打印的‘+’;若和‘+’一起使用,由于其优先级较低,效果会被‘+’覆盖:
printf("this is /% -6d/\n", 65);
输出:this is / 65 /
可以看到65前面有一个空格。
‘0’:对于所有的数字格式,用前导0而不是空格来填充空白;若指定了整数精度或‘-’,则该标志失效:
printf("this is /%05d/\n", 65);
‘#’:主要用来打印八进制或十六进制的前导符号,偶尔也会配合浮点类型使用:
printf("this is /%#5x/\n", 65);
printf("this is /%#5o/\n", 65);
输出:this is / 0x41/
this is / 0101/
用于不同数字类型转换的各个修饰符,它们配合数字类型说明符一起使用:
h: 表示一个short 或 unsigned short ,如 %hd
hh:表示一个signed char 或 unsigned char,如%hhu %hhx
l:表示一个long或unsigned long,如%lo,%ld
ll:long long 或 unsigned long long,%llx
L:long double
t:只能配合整数类型,表示指针之间的差所对应的类型,注意不是指针类型本身,%td
z:只能配合整数类型,表示一个size_t值,即sizeof返回值的类型,%zd