调用带有 va_list 参数的函数需要在开头使用 va_start() 吗?
Calling a function with va_list argument needs va_start() at the beggining?
具有以下 header 的函数:
int max(int n, va_list vals)
函数内部调用:
int max_first(int n, ...)
需要在 body 的开头进行 va_start(vals, n)
调用?我试过没有,但它有效,但我不明白哪种方法是正确的。
int max(int n, va_list vals)
{
va_start(vals, n);
// etc
}
让我们从一些背景开始:根据文档,在任何 va_list
:
上调用 va_arg
之前,您需要先调用 va_start
"va_start 应该在对 va_arg" 的任何调用之前使用有效 va_list 对象 ap 的实例调用。 (Source)
“在调用 va_arg 之前,ap 必须通过调用 va_start 或 va_copy 进行初始化,中间不调用 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_start
调用初始化的 va_list
。理由是它在技术上不是“可变的”并且并不真正“拥有”va_list
。它只是接受它作为来自其他来源的输入。
实际的可变参数函数 int max_first(int n, ...)
应该是创建 va_list
并在将其传递到任何地方之前调用 va_start
启动它的函数。
不过,据我所知,没有办法检查 va_list
是否已经调用了 va_start
。并且不能保证它会在传递给您的函数之前被调用,所以我怀疑这必须通过文档和约定来强制执行。
您必须在 max_first
中用 va_start
初始化 va_list
。但是你不能在max
中重做它,因为那个函数没有必要的调用帧信息。
问题是
int max(int n, va_list vals)
Called inside the function:
int max_first(int n, ...)
Needs a va_start(vals, n)
invocation at the body's beginning?
不,不会,而且一定不会,正确的格式如下:
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
。
具有以下 header 的函数:
int max(int n, va_list vals)
函数内部调用:
int max_first(int n, ...)
需要在 body 的开头进行 va_start(vals, n)
调用?我试过没有,但它有效,但我不明白哪种方法是正确的。
int max(int n, va_list vals)
{
va_start(vals, n);
// etc
}
让我们从一些背景开始:根据文档,在任何 va_list
:
va_arg
之前,您需要先调用 va_start
"va_start 应该在对 va_arg" 的任何调用之前使用有效 va_list 对象 ap 的实例调用。 (Source)
“在调用 va_arg 之前,ap 必须通过调用 va_start 或 va_copy 进行初始化,中间不调用 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_start
调用初始化的 va_list
。理由是它在技术上不是“可变的”并且并不真正“拥有”va_list
。它只是接受它作为来自其他来源的输入。
实际的可变参数函数 int max_first(int n, ...)
应该是创建 va_list
并在将其传递到任何地方之前调用 va_start
启动它的函数。
不过,据我所知,没有办法检查 va_list
是否已经调用了 va_start
。并且不能保证它会在传递给您的函数之前被调用,所以我怀疑这必须通过文档和约定来强制执行。
您必须在 max_first
中用 va_start
初始化 va_list
。但是你不能在max
中重做它,因为那个函数没有必要的调用帧信息。
问题是
int max(int n, va_list vals)
Called inside the function:
int max_first(int n, ...)
Needs a
va_start(vals, n)
invocation at the body's beginning?
不,不会,而且一定不会,正确的格式如下:
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
。