使用va_list参数调用函数需要在开始时使用va_start?

问题描述

具有以下标头的函数

int max(int n,va_list vals)

函数内部调用

int max_first(int n,...)

在身体开始时需要va_start(vals,n)调用吗?我尝试了一下却没有效果,但是我不知道哪种方法是正确的。

int max(int n,va_list vals)
{
    va_start(vals,n);
    // etc
}

解决方法

问题是

int max(int n,va_list vals)

在函数内部调用:

int max_first(int n,...)
 

在身体开始时需要va_start(vals,n)调用吗?

否,不是,并且一定不是,正确的模式如下:

int max_first(int n,...) {
    va_list vals;
    va_start(vals,n);
    int rv = max(n,vals);
    va_end(vals);
    return rv;
}

然后

int max(int n,va_list vals) {
    for (int i = 0; i < n; i ++) {
        int val = va_arg(vals,int);
        ...
    }

    ...
}

即您只能在具有va_start的函数中调用...,并且需要在...之前传递参数,并且每次调用va_start时都必须跟在后面va_end具有相同的值,如果将其传递给函数,则必须随后立即调用va_end,而不能在调用函数中使用它;如果要再次处理参数,则必须然后再次调用va_start

,

您必须在va_list中用va_start初始化max_first。但是您不能在max中重做它,因为该函数没有必要的调用框架信息。

,

让我们从一些背景开始:根据文档,您需要先调用va_start,然后在任何va_arg上调用va_list

  • “在对va_arg进行任何调用之前,应先将实例与有效va_list对象ap一起调用va_start”。 (Source

  • “在调用va_arg之前,必须先通过调用va_start或va_copy来初始化ap,而不能干预va_end”。 (Source

我想不打电话给va_start未定义的行为,但是我找不到这样的特定标注。

在您的问题中,函数int max(int n,va_list vals)不是“真正的”可变参数,因为它接受固定数量的参数:2。它们是int nva_list vals

每个documentation“可变参数函数的声明使用省略号作为最后一个参数,例如int printf(const char* format,...);

因此,这取决于您如何实现它,但是我建议记录int max(int n,va_list vals)以接受已经通过va_list调用初始化的va_start。理由是它在技术上不是“可变的”,并且实际上并不是“拥有” va_list。它只是接受它作为其他来源的输入。

实际的可变参数函数int max_first(int n,...)应该是创建va_list并通过调用va_start进行初始化的函数,然后再将其传递到任何地方。

据我所知,无法检查va_list是否已调用va_start。而且不能保证在将其传递给您的函数之前会先调用它,因此我怀疑这必须由文档和约定来强制执行。