C语言中变参函数的实现
C语言的可变参数函数的实现需要使用头文件stdarg.h,在该头文件中定义了一个变量类型va_list和三个宏va_start、va_arg、va_end(),下面将在代码中讲解这几个宏的使用方法。
手动指定可变参数的类型
第一种方法是在函数内部手动指定可变参数的类型。首先需要知道可变参数的个数,并作为第一个参数传入。由于函数参数入栈的顺序是从右往左,因此必须把参数个数写在最左边,可变参数写右边。
// 可变参数的实现
#include <stdarg.h>
int ShowVarList(int n,...){ // 用...来表示可变参数,且个数为n -->第一步
va_list ap; // 创建va_list类型的变量ap,准备用来接收可变参数 -->第二步
va_start(ap,n); // 用va_start宏把ap初始化为有n个元素的参数列表 -->第三步
// 本质上是给每个参数分配动态内存
int toc = va_arg(ap,int); // va_arg宏接收两个参数:参数列表和参数类型。调用
// 第n次,则返回参数列表的第n个元素(类似readdir),
// 需要手动指定第n个参数的类型 -->第四步
double tak = va_arg(ap,double); // 继续访问下一个参数...
va_end(ap); // 最后要释放参数列表的动态内存
}
自动检测可变参数的个数和类型
手动指定只在某些特殊场合有用,通常情况下需要自动检测可变参数的个数和类型(如printf,sprintf等)。其实现步骤和上述过程类似,只是把参数个数换成了一个格式化字符串,然后通过处理该字符串,判断参数的个数和类型(格式化字符串的处理过程比较复杂,具体细节可以看printf的源码)。这里不分析如何处理格式化字符串,而是直接使用库函数来实现自定义的可变参函数。
这里要用的库函数是vsnprintf,在头文件stdarg.h中定义:
#include <stdarg.h>
int vsprintf(char *str, const char *format, va_list ap); // 不限制输出字符串长度
int vsnprintf(char *str, size_t size, const char *format, va_list ap); // 限制长度,防止数组越界
/*
用途:将参数列表ap按format的格式输出到str中,并限制总字符个数最多size
参数说明:
str:输出字符串,通常是数组首地址
size:输出字符串的最大长度
format:格式化字符串
ap:参数列表
返回值:返回生成字符串的长度,如果大于size,则只会把前size个拷贝到str中,失败返回负值
*/
// 根据示例结合实际情况修改
#include <stdio.h>
#include <stdarg.h>
#define MAX_SIZE 1000
char print_buf[MAX_SIZE]; // 输出字符串存入的数组
int PrintVatList(const char* format,...){
int len;
va_list ap;
va_start(ap,format); // 初始化参数列表
len = vsnprintf(print_buf, MAX_SIZE, format, ap);
va_end(ap); // 释放动态内存
/*
处理printf_buf的代码
*/
return len;
}