2014-09-03 36 views
6

我有以下代码:多个va_end调用的顺序是否重要?

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]); 

我看各个网站的文档上va_startva_end,以及所有他们说的是,va_end应该调用每个va_start调用函数返回前。

我不确定的是电话的顺序是否重要。具体地讲,是

va_end(va[0]); 
va_end(va[1]); 

在上述示例代码sementically相同

va_end(va[1]); 
va_end(va[0]); 

+1

您可能也有兴趣'va_copy'。 – 2014-09-03 19:21:39

回答

1

一些 [旧]实施方式中,va_start扩展到左括号{其次是一些声明,va_end扩展到右括号}可能通过一些“修订”之前。道德上他们应该匹配。在实践中,经常但不总是,秩序并不重要(但原则上它确实很重要)。

在最近的海湾合作委员会,这些va_startva_end宏扩展到__builtin_va_start & __builtin_va_end调用所以编译器可能关心(也许在将来的某个版本),这些都是正确嵌套。见this。因此,“好”的顺序应该是:

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]); 

在实践中的va_end顺序可能不管那么多了。

缩进是我要强调的是,va_start & va_end是“筑巢”

当然,你需要调用va_arg真正找回可变参数(我希望你process正在这样做)。 stdarg(3)解释以及(对于C代码):

va_start()每次调用必须通过同样的功能对应 调用va_end()一个匹配。

注意对应字(重点是我的)。我相信这意味着va_startva_end确实是嵌套(至少原则上)。

+0

IIRC,没有执行的''''va_start'曾经那样做过。一些(预标准)''实现了,但标准C和标准C++从未有''头。 – hvd 2014-09-03 19:31:24

+0

同意。但是实现可能会做很奇怪的事情 – 2014-09-03 19:32:05

+0

除非任何一个标准需要特定的'va_end'调用顺序,否则实现不能做出奇怪的事情。 – hvd 2014-09-03 19:32:43

3

与C99标准中唯一的相关要求是:

7.15.1变量参数列表访问宏

1 [...]的va_startva_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; 
} 

这符合本标准的所有要求,所以实现必须接受它。因此,不允许使用va_end扩展为具有不匹配大括号的技巧。

实际上,我甚至都没有意识到任何当前的实现,其中va_end都有任何必要的影响。我所能找到的所有实现,至多将值(或第一个子值,取决于类型)设置为零,这将进一步使用va_arg失败,但如果省略则不会导致问题va_end从您的代码。大多数甚至没有这样做。现在,我不会真的从代码中删除它,因为有一个合法的原因,为什么一个实现(当前或未来)可能会在其va_end中实际执行某些操作,但您可以假设当前和未来的实现至少会尝试在一种符合标准要求的方式。

使用#define va_end(ap) }的历史实现就是这样:历史。他们没有在<stdarg.h>中提供该宏,他们甚至没有<stdarg.h>标题。你不应该担心他们。

+0

好的,但这只是答案的一半。很多实现都会执行不被“允许”执行的操作。这里有吗? – 2014-09-03 20:33:05

+0

@LightnessRacesinOrbit我知道一些C89之前的实现需要'va_start'和'va_end'来匹配'',但我没有意识到任何实现''时都有任何问题。另外,一般来说,“标准说它没问题”,如果备份,就足以作为答案。当然,有些bug存在实现,如果有任何主流编译器出现这些错误,在回答中提到它们是很好的,但是仅仅因为假设的错误实现对标准说的内容有所缺点对我来说是新的。 – hvd 2014-09-03 20:42:58

+0

@LightnessRacesinOrbit实际上,我最近搜索了'va_end'完成*任何操作*的实现,如果'va_end'被省略,会导致问题,但我一直没有找到任何示例。所以在实践中,我认为标准的要求比实际需要更严格。 – hvd 2014-09-03 20:44:52

相关问题