C,c++可变参数特性分析与实例

 
Category: C_C++

写在前面

最近在看的一份关于2048游戏的OpenGL实现的C语言源代码, 其中用到了一个比较独特的语法, 叫做可变参数, 乍一看还以为是C++11中引入的可变参数模板, 实际上却是C语言独有的特性, 下面来分析一下这个语法特性, 并用来实现一些小例子, 以及C和C++的这类型语法的一些对比. 参考了Wikipedia, cppreference.com和其他一些博客文章.

下面是一些需要的头文件, 这里采用了C++写, 如果用C的话改成stdarg.h之类即可

#include <cstdarg> // you need to include this to use variable numbers of args

#include <cstdio>

#include <cstdlib>

#include <ctime>

#include <climits>//INT_MAX

输出

void printArgs(int arg1, ...) {
    /* 打印函数的所有参数, 直到出现负数 */
    va_list ap;
    va_start(ap, arg1); // 捕获初始值
    // va_arg指定捕获参数的类型, 返回下一个参数
    for (int i = arg1; i > 0; i = va_arg(ap, int))
        printf("%d ", i);
    va_end(ap); //释放参数列表内存
    putchar('\n'); //以换行符结尾
}

平均值

这里我用两种方法, 分别是设置跳出条件(可以有任意数量的参数, 但是必须选用一个特定值作为跳出条件)和固定输入的数量(不能有任意数量参数, 但是不需要判断特殊值进行循环的跳出)

void calAverage(int arg1, ...) {
    /*这个函数需要给定循环跳出的条件, 这里我设置为INT_MAX */
    va_list ap;
    int i, total = 0, j = 0;

    va_start(ap, arg1);
    for (i = arg1; i != INT_MAX; i = va_arg(ap, int)) {
        total += i;
        j++;
    }
    va_end(ap);
    printf("total(%d) is: %d, average is: %.2f\n", j, total,
        (double) total / j);
}

void calAverage1(int num, ...) {
    /*这里指定了读取参数的数量, 放在第一个参数位置*/
    va_list ap;
    int i, total = 0;

    va_start(ap, num);
    for (i = 0; i < num; i++) {
        total += va_arg(ap, int);
    }
    va_end(ap);
    printf("total(%d) is: %d, average is: %.2f\n", num, total,
        (double) total / num);
}

最值

void findMax(int arg1, ...) {
    /*这个函数需要给定循环跳出的条件, 这里我设置为INT_MAX */
    va_list ap;
    int i, max1=0;

    va_start(ap, arg1);
    for (i = arg1; i != INT_MAX; i = va_arg(ap, int)) {
        max1=max1<i?i:max1;
    }
    va_end(ap);
    printf("Max value is: %d\n\n", max1);
}

完整测试代码

C-Cpp_Proj/c-varadic-args.cpp at main · Apocaly-pse/C-Cpp_Proj (github.com).

结果:

printArgs test:
84 51 
findMax test:
Max value is: 84

calAverage test:
total(6) is: 202, average is: 33.67
total(6) is: 202, average is: 33.67
calAverage time compare:
test1, CLOCKS_PER_SEC is: 1000000, total time is: 216.106000ms

test2, CLOCKS_PER_SEC is: 1000000, total time is: 213.071000ms

可见指定数量之后速度要略快一些.