va_list可变参数的秘密
我们知道在
c++
里面,如果无法确认传入的参数个数以及类型的时候,那么可以使用
省略号来指定参数列表
比如
void fun1(int a, ...)
void fun2(...)
其中比较典型的就是printf
函数
printf (const char *__restrict __fmt, …)
调用
printf(“ssss %d”,10)
那么其函数内部实现的是如何的
值得注意的是
- \1. 变参处的定义或声明, 用 … 代替参数类型.
- \2. 变参 … 只能放在参数列表最末尾.
内部实现原理
其实其内部的机制就是val_list
val_list
在stdarg.h
头文件
type va_arg(
va_list arg_ptr,
type
);
void va_end(
va_list arg_ptr
);
void va_start(
va_list arg_ptr,
prev_param
);
其中type
是指定回去参数的类型. arg_ptr
是指向参数列表的指针. pre_param
是指向最后一个显示声明的参数,用来回去第一个变长参数的位置
使用步骤
a)定义一个va_list
类型的变量,变量是指向参数的指针。
b)va_star
t初始化刚定义的变量,第二个参数是最后一个显式声明的参数(也就是...
之前的参数)。
c)va_arg
返回变长参数的值,第二个参数是该变长参数的类型。
d)va_end
将a)定义的变量重置为NULL。
具体的含义是
val_list
定义一个变量列表的指针类型
va_start
是将va_list
对象绑定到有n个变量的传入参数列表上
va_arg
是从参数列表中逐个去除数据,取出数据的类型有type
决定,返回type
类型的值.并且使得agv_ptr
指向参数列表中的下一个参数.
当函数结束的时候调用va_end
来清除va_list
指向的空间,不然会发生内存泄露
所以必须知道传入参数的个数不然va_start
无法绑定
例子
#include <stdarg.h>
#include <stdio.h>
void myprint(const char* format, ...) {
va_list va;
va_start(va, format);
char ch;
while (ch = *format++) {
if (ch == '%') {
ch = *format++;
if (ch == 's') {
char* ss = va_arg(va, char*);
while (*ss) {
putchar(*ss++);
}
} else if (ch == 'd') {
putchar(va_arg(va, int) + '0');
}
} else {
putchar(ch);
}
}
va_end(va);
}
int main() { myprint("hello world %s years %d\n", "!!!", 9); }