C语言可选性自变量(摘自C语言核心技术)
C语言允许定义自变量数量可变的函数,这称为variadic函数。这样的函数需要固定数目的强制性自变量(mandatory argument),后面是数量可变的可选性自变量。这样的函数必须有“至少一个”强制性自变量。可选性自变量的类型可能会改变,可选性自变量的数量可能由“强制性自变量的值”所决定,或者由“用来定义可选性自变量列表的特殊值”所决定。
C语言中,最有名的variadi函数范例是printf()和scanf()。这两个函数都有一个强制性自变量,也就是格式字符串;格式化字符串中的转换修饰符决定可选性自变量的类型和数量。
对于每一个强制的变量来说,函数头会显示一个适当的参数,像一般的函数声明一样。参数列表的规格是强制性参数在前(用逗号隔开),后面跟着一个逗号和省略符号(...),这个省略符号就代表可选性自变量。
variadic函数要存取可选性自变量时,必须通过一个类型为va_list的对象,它包含了自变量信息。这种类型的对象也称为“自变量指针”(argument pointer),它最少包含此堆栈中一个自变量的位置。可以使用这个自变量指针前移到下一个可选性自变量,这样的话,函数就可以存取所有的可选性自变量。va_list类型被定义在stdarg.h头文件中。
当编写支持“数量可变自变量”的函数时,必须用va_list类型定义自变量指针,以存取可选性自变量。在下面的讨论中,va_list对象被命名为argptr。可以用四个宏来处理此自变量指针,这些宏都定义在stdarg.h头文件中:
void va_start(va_list argptr, lastparam);
va_start宏使用第一个可选性自变量的位置来初始化argptr自变量指针。此宏的第二个自变量必须是“此函数最后一个有名称的参数”的名称。开始使用可选性自变量之前,你必须先调用此宏。
type va_arg(va_list argptr, type);
va_arg宏会取得目前argptr所引用的可选性自变量,也会将argptr前移到下一个自变量。va_arg宏的第二个自变量是“刚刚读入”自变量的类型。
void va_end(va_list argptr);
当不再需要自变量指针时,你必须调用va_end宏。若干想使用va_start或va_copy来重新初始化一个之前用过的自变量指针,也必须先调用va_end。
void va_copy(valist dest, va_list src);
va_copy宏使用目前的src来初始化自变量指针dest。然后就可以使用dest来存取可选性自变量列表,从src引用的位置开始。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4
5 void myprintf(const char *fmt, ...)
6 {
7 /*
8 * va_list 类型用于声明一个变量, 该变量将依次引用各参数.
9 * va_start 将变量初始化为指向第一个无名参数的指针.
10 * va_arg 该函数都将返回一个参数, 并将变量指向下一个参数.
11 */
12 va_list ap;
13 va_start(ap, fmt);
14 const char *p;
15 for ( p = fmt; *p; p++) {
16 if (*p == '%') {
17 switch(*++p) {
18 case 'd':
19 printf("%d", va_arg(ap, int));
20 break;
21 case 'f':
22 printf("%f", va_arg(ap, double));
23 break;
24 case 's':
25 printf("%s", va_arg(ap, char *));
26 break;
27 default:
28 break;
29 }
30 } else {
31 putchar(*p);
32 }
33 }
34 va_end(ap);
35 }
36 int main(int argc, char *argv[])
37 {
38 myprintf("%s = %d / %f\ = %f\n", "100 / pi", 100, 3.1415926, 100 / 3.1415926);
39 getch();
40 return 0;
41 }
执行结果为,在控制台输出:
100 / pi = 100 / 3.141593 = 31.830989