printf函数的正确声明形式为:
int printf(char *fmt, ...)
其中,省略号表示参数表中参数的数量和类型是可变的。省略号只能出现在参数表的尾部。
这里编写一个与printf函数功能类似的函数miniprintf来演示变长参数表的实现,声明如下:
miniprintf(char *fmt, ...)
标准头文件<stdarg.h>中包含了一组宏定义,它们对如何遍历参数表进行了定义:
(1)va_list类型用于声明一个变量,该变量将依次引用各参数,程序中即ap。
(2)宏va_start将ap初始化为指向第一个无名参数的指针。在使用ap之前,该宏必须被调用一次。
参数表必须至少包括一个有名参数,va_start将最后一个有名参数作为起点。
(3)每次调用va_arg,该函数返回一个参数,并将ap指向下一个参数。va_arg使用一个类型名来
决定返回的对象类型、指针的移动步长。
(4)va_end在函数返回之前调用,做一些清理工作。
以下是miniprintf函数的实现及测试:
1 #include <stdarg.h> 2 #include <stdio.h> 3 4 void miniprintf(char *fmt, ...); 5 6 int main() 7 { 8 miniprintf("I will print %d %s floats: %f %f %f\n", 3, "strange", 0.1, 0.998, 0.235); 9 return 0; 10 } 11 12 void miniprintf(char *fmt, ...) 13 { 14 va_list ap; 15 char *p, *sval; 16 int ival; 17 double dval; 18 19 va_start(ap, fmt); 20 for (p = fmt; *p; p++) { 21 if (*p != '%') { 22 putchar(*p); 23 continue; 24 } 25 switch (*++p) { 26 case 'd': 27 ival = va_arg(ap, int); 28 printf("%d", ival); 29 break; 30 case 'f': 31 dval = va_arg(ap, double); 32 printf("%f", dval); 33 break; 34 case 's': 35 for (sval = va_arg(ap, char *); *sval; sval++) 36 putchar(*sval); 37 break; 38 case '\n': 39 printf("\n"); 40 break; 41 default: 42 putchar(*p); 43 break; 44 } 45 } 46 va_end(ap); 47 }
注:以上内容基本摘自《The C Programming Language》,非原创。