C解析之十二C语言prinft函数的秘密
前言:从C语言的第一个程序Hello World开始,到目前所写的几乎所有C程序都有它的出场,它便是: 标准化输出函数printf。printf超高的出场率让人对它习以为常,似乎printf函数的独特性也不被人所注意。
1.变长参数:不可思议
你可能没有注意:printf函数的参数是变长参数。
printf("Hello World !");
ptintf("%d",number);
printf("Two number:%d %d",number1,number2);
首先,试图从函数相关的知识解析这个问题,... ,最后只能得出一个结论:不可思议。
2.printf常见使用格式:
printf(char *format,arg1,arg2 ...);
其中format称为格式化字符串:包含普通字符和转换字符。输出时,普通字符原封不动地复制到输出流中,转换字符则用于控制参数的输出方式。
arg1,arg2 ...是参数列表。
如:printf("Hello World !");
格式化字符串仅包含普通字符串"Hello World !",则"Hello World !"按原样输出。
再如: printf("Two number:%d %d",number1,number2);
格式化字符串包含普通字符串"Two number:"和转换字符串"%d %d","Two number:"原样输出,转换字符串则用于控制number1,number2的输出。
3.prinft定义格式:
int printf(char *format, ... )
此处的省略号...表示参数的数量与类型可变。
关键:如何处理...代表的参数表,它甚至连名字都没有。答案在标准头文件<stdarg.h>中的一组宏定义,这组宏定义提供了遍历参数表的方法。va_list类型用于声明一个变量,该变量将依次引用参数表的各个参数。va_start将va_list变量指向第一个无名参数。va_arg返回参数表中的一个参数,并将va_list变量指向下一个无名参数。va_arg根据一个数据类型名决定返回参数的类型与指针移到的步长。va_end用于最后做一些清理工作。
4.编写自己的printf函数:
实现一个Myprintf很容易吧,出于复杂度与突出重点的考虑,Myprintf没有实现自己的int,double转换,它的int,double的转换实际上借用了printf的转换,所以需要包含stdio.h,但不要纠结于这些无关紧要的细节。通过Myprintf,printf如何使用变长的参数表,printf的工作机制便清晰地浮出水面。