C语言中的变长参数

时间:2019-02-26 00:19:54

标签: c variadic-functions

为什么我必须在c int函数中使用var_args类型的变量?像printf一样,它是一个内置函数,不需要在输入各种变量之前声明参数的长度...

3 个答案:

答案 0 :(得分:1)

C标准不需要带有可变参数列表的函数来具有任何特定的参数类型。

但是,取决于对va_arg进行适当调用的功能。为此,该函数必须具有某种方式来知道已传递了哪些参数。您可以按照自己希望的任何方式实现该要求,包括:

  • printf一样,使用包含表示参数类型的转换说明符的格式字符串。
  • 传递对每个参数的数字和类型的任何描述。将它们全部编码为一个数组,传递几个描述其余参数的参数,描述一个参数,然后具有该参数,然后描述下一个参数,然后具有该参数,依此类推。
  • 从请求该函数执行的操作中推导出参数。例如,open调用可能带有标志,该标志指示应创建文件还是仅打开现有文件。如果要创建文件,则可以使用一个附加参数,指示要在该文件上设置的权限,而如果仅打开现有文件,则不采用该参数。

答案 1 :(得分:1)

C不允许变量参数函数选择采用零参数。也就是说,...之前必须有一个命名参数。

对于printf,命名参数是格式字符串。解析格式字符串时,可以推导出下一个参数的类型,并且可以正确调用va_arg宏。

如果所有参数的类型相同,则可以使用命名参数指示要传入的参数的数量。例如,如果要传入许多字符串:

void foo_strings (int n, ...) {
    va_list ap;
    va_start(ap, n);
    while (n--) {
        const char *s = va_arg(ap, const char *);
        foo(s);
    }
    va_end(ap);
}

但是,您可以很容易地使用NULL来指示没有更多的字符串。然后,第一个参数可以用于其他功能,例如指向函数。

void foo_string (void (*foo)(const char *), ...) {
    va_list ap;
    va_start(ap, n);
    const char *s = va_arg(ap, const char *);
    while (s != NULL) {
         foo(s);
         s = va_arg(ap, const char *);
    }
    va_end(ap);
}

答案 2 :(得分:1)

答案与编译器调用约定有关。这是一个稍微简化的解释:

基本上,当编译器遇到带有N个参数的函数调用时,它将生成将N个参数压入堆栈的代码。
当编译器编译一个带有N个参数的函数时,它会生成代码以将N个参数弹出堆栈。

没有“秘密”信息告诉函数推入了多少个参数。对于普通函数,参数的数量和类型是一致的,仅是因为调用代码中的函数原型与函数定义一致。

对于可变函数,不可能依赖函数定义。 ...的字面意思是“我们不知道要推送哪些参数。因此,需要为参数说明提供一个替代来源。一种简单的实现方式是确保第一个参数是固定计数-size个参数。

printf和家人使用不同的方法。格式字符串定义了它将使用的类型和多少个参数。

相关问题