C++查漏补缺——可变参数的初步理解
可变参数:
含义:函数参数个数可以变,在C#中有专门的关键字parame。
格式:用三个点“...”来表示,类型可以是int、double、char*、类、结构体等等。
变参宏(Variadic Macros):
void func1(char nparam, ...){
return;
}
#define func2(...) {func1(...);}
编译的时候会提示func2为非法表达式。
#define func3(...) {func1(__VA_ARGS__);}
__VA_ARGS__是变参宏。表示前面定义的"..."。只有三点用在宏定义上,__VA_ARGS__才有效。
三点”...“的操作:
(环境:
)
va_list
可以在vadefs.h找到其定义。
typedef char * va_list;
va_start、va_end、va_arg
可以在stdarg.h找到其定义。
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //获取第一参数的地址,ap为取出数据的指针,v为数据源的指针
#define va_end(ap) ( ap = (va_list)0 ) //将指针置无效
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数的地址,
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) //计算参数地址间间隔大小
这里要注意面对不同类型,用法也有一定的差异。
假设传入的int类型:
定义:
void func_Num(int nSrc,...)
{
va_list cl;
va_start(cl, nSrc);
printf("Num:%d\n", *cl);
va_arg(cl, int);
printf("Num:%d\n", *cl);
va_end(cl);
}
调用:
func_Num(12,23,34,45);
但是如果传入的参数是char*类型:
定义:
void func_Charp(char* chSrc,...)
{
printf("->:%d\n", chSrc);
va_arg(cchSrc, char*);
printf("->:%d\n", chSrc);
va_arg(chSrc, char*);
printf("->:%d\n", chSrc);
}
调用:
func_Charp("abc", "def", "ghi");
解析一下:
先以func_Num为例:
(1)参数列表存入的是一个栈结构,自第一个元素nSrc元素起,元素地址间的偏移量为_INTSIZEOF(type)。
(2)va_start(cl, nSrc)等价与cl= (va_list)&nSrc + _INTSIZEOF(nSrc),由于nSrc就是第一个参数,即(va_list)&nSrc表示的是第一个参数的地址,加上_INTSIZEOF(type)的偏移量之后便是第二个元素的地址,于是函数中第一次调用va_start获得就是参数列表的第二个函数,即”...“所表示的第一个参数,如果没有chSrc,意味没有第一个元素的位置可参考,无法拿到下一个元素的位置。
为什么存在不同就需要理解参数的存储。
浙公网安备 33010602011771号