可变参数列表


头文件<stdarg.h>提供了遍历未知数目和类型的函数参数表的功能。该头文件的实现因不同的机器而不同,但提供的接口是一致的。
假定函数 f 带有可变数目的实际参数,lastarg 是它的最后一个命名的形式参数(参数列表必须至少包括一个命名参数)。那么,在函数 f 内声明一个类型为 va_list 的变量 ap (argument pointer),它将依次指向每个实际参数。

 

va_list ap;


在访问任何未命名的参数前,必须用 va_start 宏初始化 ap 一次。(va_start 将最后一个命名参数作为起点,将 ap 初始化为指向第一个未命名参数的指针)

va_start(va_list ap, lastarg);

此后,每次执行宏 va_arg 都将返回一个参数,并将 ap 指向下一个参数。 va_arg 使用一个类型名来决定返回的对象类型、指针移动的步长。

Type va_arg(va_list ap, Type);

在所有的参数处理完毕之后,且在退出函数 f 之前,必须调用宏 va_end 以完成一些必要的清理工作。

void va_end(va_list ap);

Example


下面以实现函数printf的一个最简单版本为例,介绍如何以可移植的方式编写可处理变长参数列表的函数。因为我们的重点在于参数的处理,所以,函数minprintf只处理格式字符串和参数,格式转换则通过调用函数printf实现。
函数printf的正确声明形式为:

 

int printf(char *fmt, ...)

其中,省略号表示参数表中参数的数量和类型是可变的。省略号只能出现在参数表的尾部。
因为minprintf函数不需要像printf函数一样返回实际输出的字符数,因此,我们将它声明为下列形式:

void minprintf(char *fmt, ...)

编写函数minprintf的关键在于如何处理一个甚至连名字都没有的参数表。

#include <stdio.h>
#include <stdarg.h>

/* minprintf 函数:带有可变参数表的简化的printf函数 */
void minprintf(char *fmt, ...)
{
    va_list ap;  /* 依次指向每个无名参数 */
    char *p, *sval;
    int ival;
    double dval;

    va_start(ap, fmt);  /* 将 ap 指向第一个无名参数 */
    for (= fmt; *p; p++) {
        if (*!= '%') {
            putchar(*p);
            continue;
        }
        switch (*++p) {
            case 'd':
                ival = va_arg(ap, int);
                printf("%d", ival);
                break;
            case 'f':
                dval = va_arg(ap, double);
                printf("%f", dval);
                break;
            case 's':
                for (sval = va_arg(ap, char *); *sval; sval++)
 putchar(*sval);
                break;
            default:
                putchar(*p);
                break;
        }
    }
    va_end(ap); /* 结束时的清理工作 */
}
posted on 2012-06-05 12:00  一个人的天空@  阅读(884)  评论(0编辑  收藏  举报