1 什么是可变参数
可变参数是 C 语言和 C++ 语言中的一个特性,它允许函数定义可变数量和可变类型的参数。例如,printf
、scanf
等函数的实现就使用了可变参数,以下是printf
和scanf
的函数声明:
int printf(const char *, ...); int scanf(const char *, ...);
在形参列表里,省略号...
即为可变参数列表,用于表示可变参数。
2 如何处理可变参数
在C/C++语言中,提供了头文件<stdarg.h>
用于处理可变参数。通过引用该头文件,我们可以使用在该头文件中提供的一些可变参数处理宏和处理函数。
2.1 可变参数宏
C99标准新增的__VA_ARGS__
预定义标识符即为可变参数宏,其用于在宏定义中代表可变参数列表。通过它,我们可以在宏定义时传入可变参数,并在宏展开时将这些参数插入到指定的位置。如下所示,我们定义了一个打印调试信息的宏,且在每次输出时都自动添加换行符,使用__VA_ARGS__
来接收和展开可变参数:
#include <stdio.h> #ifdef DEBUG #define DEBUG_PRINT(fmt, ...) \ do { \ printf(fmt "\n", ##__VA_ARGS__); \ } while (0) #else #define DEBUG_PRINT(fmt, ...) #endif
在上面这个例子中,我们需要额外注意##
运算符。##
运算符的具体用法在《[C/C++]# 和 ## 运算符详解》这篇文章中有介绍,其是记号粘贴运算符,用于将两个记号粘连为一个记号,但是在此处,其还有一个额外的用法,即用于去掉当可变参数宏__VA_ARGS__
为空时,多余产生的逗号。
2.2 可变参数解析宏
对于可变参数函数,C/C++语言提供了以下可变参数解析宏用于处理函数参数:
- va_list:一种用于存储可变参数信息的类型,用于声明一个用于访问函数可变参数的变量
- va_start(ap, param):用于初始化
va_list
类型的变量,使其指向函数参数列表中的第一个可变参数 - va_arg(ap, type):用于访问
中的下一个可变参数,并将其转换为指定的类型va_list
- va_end(ap):用于清理
变量,在调用va_list
之后必须调用va_start
va_end
通过灵活使用这些宏,可以省去解析可变参数的麻烦,以下是一个简单的使用示例:
#include <stdio.h> #include <stdarg.h> void print_numbers(int count, ...) { va_list args; va_start(args, count); // 初始化 va_list 变量 for (int i = 0; i < count; i++) { int num = va_arg(args, int); // 获取下一个 int 类型的参数 printf("%d\n", num); } va_end(args); // 清理 va_list 变量 } int main() { print_numbers(3, 10, 20, 30); // 打印 10, 20, 30 return 0; }
2.3 可变参数函数
C/C++语言提供了一些可以直接处理可变参数的函数,例如vprintf
、
、vsprintf
、vsnprintf
和vfprintf
等,下面讲解vsfscanf
vprintf
函数的使用示例,其余函数的用法也基本大差不差。
vprintf
函数的函数原型如下所示:
#include <stdio.h> int vprintf(const char *format, va_list args);
- 形参:
- format:这是一个格式化字符串,指定了输出的格式
- args:这是一个
va_list
类型的参数,表示一个变参列表
- 返回值:返回输出的字符数(不包括终止的空字符),如果发生错误,则返回一个负数
vprintf
函数的使用示例如下所示,演示了如何实现一个自定义的打印函数:
#include <stdio.h> #include <stdarg.h> // 自定义函数,接受一个格式化字符串和一个可变参数列表 void my_print(const char *format, ...) { va_list args; va_start(args, format); // 初始化 va_list 类型的变量 args vprintf(format, args); // 使用 vprintf 输出格式化字符串 va_end(args); // 清理 va_list 类型的变量 } int main() { my_print("Hello, %s! You have %d new messages.\n", "Alice", 5); return 0; }