如何知道va_list的最后一个参数?

时间:2014-05-14 06:23:38

标签: c optional-parameters variadic-functions

我正在阅读如何将可选参数传递给函数。但我无法理解这些。当我看到例子时,它们令人困惑,有点复杂。所以我刚开始用一个非常简单的程序来完成我迄今所理解的内容。

以下程序只打印变量。

void print(int x, ...)
{
        va_list ap;
        int i = 4;     // I know I'm passing only 4 opt variables. 
        int num;

        va_start(ap, x);
        while(i--) {         // How to know how many variables came in real time?
                num = va_arg(ap, int);
                printf("%d\n", num);
        }
        va_end(ap);
        return;
}

int main()
{
        print(1,2,3,4,5);
        return 0;

}

我不知道上面的程序是对还是不对。但它正在发挥作用。当我将i值更改为5打印垃圾时。如何知道我得到了多少论点(如argc中的main)?

3 个答案:

答案 0 :(得分:8)

无法知道从变量参数函数中传递了多少参数,这就是为什么诸如printf之类的函数使用特殊格式字符串来告诉函数预期有多少参数

另一种方式当然是传递"额外"参数作为第一个参数,如

print(4, 1, 2, 3, 4);

或者有一个特殊的值不能作为最后一个参数列在列表中,比如

print(1, 2, 3, 4, -1);

您还必须注意,传递给函数的最后一个非-a参数(在您的情况下名为num的参数)不包含在va_list中,因此在使用4显示的代码作为硬编码参数的情况,当<{1}}参数传递1然后传递三个num时,仍然打印垃圾{1}}参数。

还要小心,因为你使用va_list作为参数和局部变量名。

答案 1 :(得分:7)

您可以查看NARGS macro

改编自您的代码:

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

#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define print(...) fnprint(NARGS(__VA_ARGS__), __VA_ARGS__)

void fnprint(int n, ...)
{
        va_list ap;
        int num;

        va_start(ap, n);
        while (n--) {
                num = va_arg(ap, int);
                printf("%d\n", num);
        }
        va_end(ap);
        return;
}

int main(void)
{
        print(1, 2, 3, 4, 5);
        return 0;
}

修改 如果要对宏和函数使用相同的名称,请使用()停止预处理器扩展函数定义:

#define print(...) print(NARGS(__VA_ARGS__), __VA_ARGS__)

void (print)(int n, ...) /* Note () around the function name */
{
  ...

编辑2:使用复合文字(std 99)和sizeof的另一种(丑陋)方法(但不限制args数量):

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

#define print(...) print(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__)

void (print)(int n, ...)
{
    va_list ap;
    int num;

    va_start(ap, n);
    while (n--) {
        num = va_arg(ap, int);
        printf("%d\n", num);
    }
    va_end(ap);
    return;
}

int main(void)
{
    print(1, 2, 3, 4, 5);
    return 0;
}

print扩展为:

print(sizeof((int []) {1, 2, 3, 4, 5}) / sizeof(int), 1, 2, 3, 4, 5);

print(1, 2, 3, a_var++, 4, 5);print(1, 2, some_func_returning_int(), 4, 5);等结构会对a_var++some_func_returning_int()进行两次评估,这是个大问题。

答案 2 :(得分:0)

int和字符串的另一种丑陋方式:

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

#define print(...) fnprint("{" # __VA_ARGS__ )

fnprint(char *b) {
    int count = 0, i;
    if (b[1] != '\0') {
        for (i =2; b[i]; i++) {
            if (b[i] == ',')
               count++;
        }
        count++;
    }
    printf("\ncount is %i\n", count);
}

int main(void)
{
        print();
        print("1", "2");
        print(1, 2, 3, 4, 5);
        return 0;
}