问题描述
具有以下标头的函数:
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 n
和va_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
。而且不能保证在将其传递给您的函数之前会先调用它,因此我怀疑这必须由文档和约定来强制执行。