Variadic arguments
可变参数函数是指可以接受不同数量参数调用的函数。
只有原型化的 函数声明 可以是可变参数的。这通过形如 ... 的参数表示,该参数必须出现在参数列表的最后位置 且必须跟随至少一个命名参数 (C23前) 。省略号参数与其前面的参数必须使用 , 进行分隔。
// 原型声明 int printx(const char* fmt, ...); // 以此方式声明的函数 printx("hello world"); // 可使用一个 printx("a=%d b=%d", a, b); // 或多个参数调用 int printz(...); // 自 C23 起及在 C++ 中有效 // C23 前错误:... 必须至少跟随一个命名参数 // int printy(..., const char* fmt); // 错误:... 必须是最后一个参数 // int printa(const char* fmt...); // C 语言错误:要求有 ',';C++ 中有效
在 函数调用 时,属于可变参数列表的每个实参都会经历特殊的隐式转换,称为 默认实参提升 。
在使用了可变参数的函数体内,可以通过
<stdarg.h>
库工具
来访问这些参数的值:
|
定义于头文件
<stdarg.h>
|
|
|
启用可变参数函数的参数访问
(函数宏) |
|
|
访问下一个可变参数函数的参数
(函数宏) |
|
|
(C99)
|
创建可变参数函数参数的副本
(函数宏) |
|
结束可变参数函数的参数遍历
(函数宏) |
|
|
持有
va_start
、
va_arg
、
va_end
和
va_copy
所需的信息
(类型定义) |
|
目录 |
注释
尽管旧式(无原型的)
函数声明
允许后续函数调用使用任意数量的参数,但它们不允许是可变参数的(自C89起)。此类函数的定义必须指定固定数量的参数,且不能使用
stdarg.h
宏。
// 旧式声明,已在 C23 中移除 int printx(); // 以此方式声明的函数 printx("hello world"); // 可被一个 printx("a=%d b=%d", a, b); // 或多个参数调用 // 这些调用中至少有一个的行为是未定义的,具体取决于 // 函数定义时设定的形参数量
示例
#include <stdio.h> #include <time.h> #include <stdarg.h> void tlog(const char* fmt,...) { char msg[50]; strftime(msg, sizeof msg, "%T", localtime(&(time_t){time(NULL)})); printf("[%s] ", msg); va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); } int main(void) { tlog("logging %d %d %d...\n", 1, 2, 3); }
输出:
[10:21:38] logging 1 2 3...
参考文献
- C17 标准 (ISO/IEC 9899:2018):
-
- 6.7.6.3/9 函数声明符(包含原型)(页码: 96)
-
- 7.16 可变参数 <stdarg.h> (页码: 197-199)
- C11 标准 (ISO/IEC 9899:2011):
-
- 6.7.6.3/9 函数声明符(包含原型)(页码: 133)
-
- 7.16 可变参数 <stdarg.h> (页码: 269-272)
- C99标准(ISO/IEC 9899:1999):
-
- 6.7.5.3/9 函数声明符(包含原型)(第119页)
-
- 7.15 可变参数 <stdarg.h>(第249-252页)
- C89/C90 标准 (ISO/IEC 9899:1990):
-
- 3.5.4.3/5 函数声明符(包含原型)
-
- 4.8 可变参数 <stdarg.h>
参见
|
C++ 文档
关于
可变参数
|