STDARG - Linux手册页

时间:2019-08-20 18:01:22  来源:igfitidea点击:

Linux程序员手册 第3部分
更新日期: 2020-06-09

名称

stdarg,va_start,va_arg,va_end,va_copy-变量参数列表

语法

#包括

无效va_start(va_list ap,last);
输入va_arg(va_list ap,type);
无效va_end(va_list ap);
无效va_copy(va_list dest,va_list src);

说明

可以使用数量众多,类型不同的参数来调用函数。包含文件声明了一个va_list类型,并定义了三个宏,用于逐步通过一个参数列表,这些参数的数量和类型对于调用的函数是未知的。

所调用的函数必须声明一个va_list类型的对象,该对象由宏va_start(),va_arg()和va_end()使用。

va_start()

va_start()宏会初始化ap,以供va_arg()和va_end()后续使用,并且必须首先调用。

参数last是变量参数列表之前的最后一个参数的名称,即调用函数知道其类型的最后一个参数。

由于此参数的地址可以在va_start()宏中使用,因此不应将其声明为寄存器变量,函数或数组类型。

va_arg()

va_arg()宏扩展为具有调用中下一个参数的类型和值的表达式。参数ap是由va_start()初始化的va_list ap。每次调用va_arg()都会修改ap,以便下一次调用返回下一个参数。参数类型是指定的类型名称,因此只需在类型上添加*即可获得具有指定类型的对象的指针的类型。

va_start()宏之后的第一次使用va_arg()宏将返回最后一个参数。连续调用将返回其余参数的值。

如果没有下一个自变量,或者类型与实际的下一个自变量的类型不兼容(根据默认自变量提升),则将发生随机错误。

如果将ap传递给使用va_arg(ap,type)的函数,则在该函数返回后ap的值是不确定的。

va_end()

va_start()的每次调用必须与同一函数中va_end()的相应调用相匹配。调用va_end(ap)之后,变量ap未定义。可以多次遍历列表,每个遍历都由va_start()和va_end()括起来。 va_end()可以是宏或函数。

va_copy()

va_copy()宏将(先前初始化的)变量参数列表src复制到dest。行为就像是使用相同的最后一个参数将va_start()应用于dest,然后是用于达到src当前状态的va_arg()调用次数相同。

一个明显的实现是让va_list是指向可变参数函数的堆栈框架的指针。在这样的设置中(到目前为止是最常见的),似乎没有什么反对任务的

va_list aq = ap;

不幸的是,也有一些系统使它成为指针数组(长度为1),并且有一个需求

va_list aq;
*aq = *ap;

最后,在将参数传递到寄存器中的系统上,va_start()可能有必要分配内存,在其中存储参数,并指示下一个参数,以便va_arg()可以逐步通过列表。现在,va_end()可以再次释放分配的内存。为了适应这种情况,C99添加了一个宏va_copy(),因此上述分配可以替换为

va_list aq;
va_copy(aq, ap);
...
va_end(aq);

va_copy()的每次调用必须与同一函数中va_end()的相应调用相匹配。一些不提供va_copy()的系统改而使用__va_copy,因为这是提案草案中使用的名称。

属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
va_start(),va_end(),va_copy()Thread safetyMT-Safe
va_arg()Thread safetyMT-Safe race:ap

遵循规范

va_start(),va_arg()和va_end()宏符合C89。 C99定义了va_copy()宏。

BUGS

与历史上的varargs宏不同,stdarg宏不允许程序员编写没有固定参数的函数。此问题主要在将varargs代码转换为stdarg代码时产生,但对于希望将其所有参数传递给带有va_list参数的函数(例如vfprintf(3))的可变参数函数,也带来了困难。

示例

函数foo接受一串格式字符,并根据类型打印出与每个格式字符关联的参数。

#include <stdio.h>
#include <stdarg.h>

void
foo(char *fmt, ...)   /* '...' is C syntax for a variadic function */

{
    va_list ap;
    int d;
    char c, *s;

    va_start(ap, fmt);
    while (*fmt)
        switch (*fmt++) {
        case aqsaq:              /* string */
            s = va_arg(ap, char *);
            printf("string %s\n", s);
            break;
        case aqdaq:              /* int */
            d = va_arg(ap, int);
            printf("int %d\n", d);
            break;
        case aqcaq:              /* char */
            /* need a cast here since va_arg only
               takes fully promoted types */
            c = (char) va_arg(ap, int);
            printf("char %c\n", c);
            break;
        }
    va_end(ap);
}

另外参见

vprintf(3),vscanf(3),vsyslog(3)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/