可变参数函数

C语言的stdarg.h头文件中定义了一组宏,可用来实现可变参数函数,也称作不定参数函数,这类函数有以下特点:

实现可变参数函数步骤一般如下:

如何判断不定参数是否取完了呢?有两种做法:一种是在不定参数的前面加个固定参数用于描述不定参数,例如printf中的fmt参数,如果不定参数类型都相同,也可以将不定参数的个数作为最后一个固定参数;另一种做法是采用哨兵,将一个无意义的值(例如0/-1/NULL等)作为最后一个不定参数。

下面是一个例子,识别不定参数结尾采用的哨兵做法。

#include <stdio.h>
#include <stdarg.h>
enum {END, STR, DEG, HEX};
void func(char *buf, ...) {
    va_list ap;
    int type = 0, pos = 0, num;
    char *p;

    va_start(ap, buf);
    type = va_arg(ap, int);
    while (END != type) {
        if (STR == type) {
            p = va_arg(ap, char*);
            pos += sprintf(buf + pos, "[%s]", p);
        } else if (DEG == type) {
            num = va_arg(ap, int);
            pos += sprintf(buf + pos, "[%d]", num);
        } else if (HEX == type) {
            num = va_arg(ap, int);
            pos += sprintf(buf + pos, "[0x%X]", num);
        }
        type = va_arg(ap, int);
    }
    buf[pos] = 0;
}
int main() {
    char buf[128];
    func(buf, STR, "seventeen", DEG, 17, HEX, 17, END);
    puts(buf);
    return 0;
}

运行结果如下:

[seventeen][17][0x11]

用不定参可以方便地封装打印函数,便于调试。

void Log(const char *fmt, ...)
{
    va_list ap;
    char timebuf[64];

    time_t t = time(NULL);
    struct tm *local = localtime(&t);
    strftime(timebuf, sizeof(timebuf), "%y-%m-%d %H:%M:%S", local);

    FILE *fp = fopen("trace.log", "a");
    if (fp && ftell(fp) > 1024 * 1024) {
        fp = freopen("trace.log", "w", fp);
    }
    if (!fp) return;

    fprintf(fp, "%s ", timebuf);
    va_start(ap, fmt);
    vfprintf(fp, fmt, ap);
    va_end(ap);
    fprintf(fp, "\n");
    fclose(fp);
}
Table of Contents