Tho*_*ing 7 c c++ variadic-functions
我有以下代码:
va_list va[2];
va_start(va[0], fmt);
va_start(va[1], fmt);
process(fmt, va);
va_end(va[0]);
va_end(va[1]);
Run Code Online (Sandbox Code Playgroud)
我已经查看了各种站点上的文档va_start和va_end,并且他们说的是在调用函数返回之前va_end应该为每个站点调用它们va_start.
我不确定的是,电话的顺序是否重要.特别是
va_end(va[0]);
va_end(va[1]);
Run Code Online (Sandbox Code Playgroud)
与...完全相同
va_end(va[1]);
va_end(va[0]);
Run Code Online (Sandbox Code Playgroud)
在上面的示例代码中?
小智 5
C99标准中唯一相关的要求是:
7.15.1 变量参数列表访问宏
1 [...]
va_start和va_copy宏的每次调用都应与va_end同一函数中相应的宏调用相匹配。
不要求多次调用的va_end顺序与 的顺序匹配va_start,或与 的相反顺序匹配va_start,因此实现需要接受任一顺序。
你甚至可以使用像这样可怕的混乱
void f(int a, ...) {
va_list ap;
goto b;
a:
va_end(ap);
return;
b:
va_start(ap, a);
goto a;
}
Run Code Online (Sandbox Code Playgroud)
这符合标准的所有要求,因此实现必须接受它。因此,即使是va_end扩展为具有不匹配的大括号的东西的技巧也是不允许的。
在实践中,我什至不知道任何当前的实施有va_end任何必要的效果。我能够找到的所有实现,最多将值(或第一个子值,取决于类型)设置为零,这将进一步使用失败,但如果您省略va_arg,则不会导致问题va_end你的代码。大多数人甚至不这样做。现在,我实际上不会将其从代码中删除,因为实现(当前或未来)实际上可能在其中执行某些操作是有正当理由的va_end,但您可以假设当前和未来的实现至少会尝试在符合标准要求的方式。
使用的历史实现#define va_end(ap) }就是:历史。他们没有在 中提供该宏<stdarg.h>,甚至没有标题<stdarg.h>。你不应该担心他们。
在某些[旧]实现上,va_start扩展为左大括号{,后跟一些声明,并va_end扩展为右大括号,}前面可能有一些“终结”。从道德上讲,他们应该匹配。在实践中,通常但并非总是,顺序并不重要(但原则上它确实很重要)。
在最近的 GCC 上,这些宏va_start和va_end宏扩展为__builtin_va_start&的调用__builtin_va_end,因此编译器可能会关心(也许在未来的某个版本中)它们是否正确嵌套。看到这个。所以“好”的顺序应该是:
va_list va[2];
va_start(va[0], fmt);
va_start(va[1], fmt);
process(fmt, va);
va_end(va[1]);
va_end(va[0]);
Run Code Online (Sandbox Code Playgroud)
实际上,顺序va_end可能并不那么重要。
我的缩进是为了强调va_start&va_end是“嵌套”
当然,您需要调用va_arg才能真正检索可变参数(我希望您process正在这样做)。stdarg(3)很好地解释了这一点(对于 C 代码):
每次调用都必须与同一函数中相应的 调用
va_start()相匹配。va_end()
注意相应的单词(重点是我的)。我相信这意味着va_start和va_end确实是嵌套的(至少在原则上)。
| 归档时间: |
|
| 查看次数: |
226 次 |
| 最近记录: |