有没有一种标准的方法来确定va_args的数量?

时间:2012-10-15 17:58:49

标签: c++ variadic-functions

我正在使用va_args在C ++中尝试变量参数。这个想法很有用,而且确实是我通过params功能在C#中使用了很多东西。让我感到沮丧的一件事是以下关于va_args的摘录:

  

另请注意,va_arg不会确定检索到的参数是否是传递给函数的最后一个参数(或者即使它是超过该列表末尾的元素)。

我发现很难相信没有办法以编程方式确定从该函数本身传递给函数的变量参数的数量。我想执行以下内容:

void fcn(int arg1 ...)
{
    va_list argList;
    va_start(argList, arg1);

    int numRemainingParams = //function that returns number of remaining parameters
    for (int i=0; i<numRemainingParams; ++i)
    {
        //do stuff with params
    }
    va_end(argList);
}

重申一下,上面的文档表明va_arg不确定检索到的arg是否是列表中的最后一个。但我觉得必须以某种方式获取这些信息。

是否有实现这一目标的标准方法?

6 个答案:

答案 0 :(得分:10)

  

我发现很难相信没有办法以编程方式确定从该函数本身传递给函数的变量参数的数量。

尽管如此,这是事实。 C / C ++不会在参数列表的末尾放置标记,因此被调用的函数实际上不知道它接收了多少个参数。如果你需要标记参数的结尾,你必须自己在列表的末尾放置一些标记。

被调用函数也不知道所提供参数的类型或大小。这就是为什么printf和朋友强迫你指定要插入到格式字符串中的值的精确数据类型的原因,以及为什么你可以通过调用带有错误格式字符串的printf来使程序崩溃。

请注意,参数传递由ABI为特定平台指定,而不是由C ++ / C标准指定。但是,ABI必须允许C ++ / C标准可实现。例如,ABI可能希望在寄存器中传递参数以提高效率,但在这种情况下可能无法轻松实现va_args。所以参数也可能在堆栈上被遮蔽。但是,几乎在任何情况下都不会标记堆栈以显示参数列表的结尾,因为C ++ / C标准不要求使这些信息可用,因此它将是不必要的开销。

答案 1 :(得分:6)

变量参数在C和C ++中的工作方式相对简单:参数只是在堆栈上推送而且被调用者有责任在某种程度上弄清楚它们有什么参数。标准中没有提供确定参数数量的方法。结果,参数的数量由一些上下文信息确定,例如,格式字符串中引用的元素的数量。

个别编译器可能知道有多少元素,但没有标准接口来获取此值。

然而,你可以做的是使用可变参数模板:你可以确定传递给函数的参数的非常详细的信息。界面看起来不同,可能有必要将参数引入某种数据结构,但从好处来看,它也适用于你无法使用变量参数传递的类型。

答案 2 :(得分:3)

不,没有。这就是变量参数不安全的原因。它们是C的一部分,它缺乏为“方便”的可变函数实现类型安全的表现力。你必须忍受这样一个事实:C包含非常正确依赖于的结构,而不仅仅是类型。这就是为什么它是一种“不安全的语言”。

不要在C ++中使用变量参数。它是一种更强大的语言,允许您编写安全的同样方便的代码。

答案 3 :(得分:1)

不,没有这样的方式。如果您有这样的需求,最好将这些函数参数打包在std::vector或类似的可以迭代的集合中。

答案 4 :(得分:1)

尽管你可能希望它是真的,但没有直接的方法来知道传递给可变函数的参数的类型或数量。

一种选择是在参数列表的末尾传递一个标记,例如EXECL():

execl (path, arg1, ... argn, NULL);

另一种方法是显式传递参数的数量(和类型),比如printf()及其格式字符串。

因此,变量函数本质上是不安全的,最轻微的错误会导致代码失败。在C ++中有一些安全的替代方法,比如传递一个向量。如果所有参数的类型不同,则可以将它们包装在boost::any等变体容器中。

答案 5 :(得分:1)

变量参数列表是一个非常古老的概念,它继承自C ++的C历史。它可以追溯到C程序员通常考虑生成汇编程序代码的时间。

那时编译器根本没有检查调用它时传递给函数的数据是否与函数预期接收的数据类型相匹配。程序员有责任做到这一点。例如,如果调用者使用char调用函数并且函数期望int程序崩溃,尽管编译器没有抱怨。

今天的类型检查可以防止这些错误,但是使用可变参数列表,您可以回到那些旧概念,包括所有风险。所以,如果你能以某种方式避免它,请不要使用它。

这个概念已有几十年历史,这可能是与安全代码的现代概念相比感觉错误的原因。