◎使用方法:
func( Type para1, Type para2, Type para3, ... )
{
/****** Step 1 ******/
va_list ap;
va_start( ap, para3 ); //定要“...”的前那个参数
/****** Step 2 ******/
//此时ap指向第个可变参数
//va_arg取得里面值
Type xx = va_arg( ap, Type );
//Type定要相同如:
//char *p = va_arg( ap, char *);
// i = va_arg( ap, );
//如果有多个参数继续va_arg
/****** Step 3 ******/
va_end(ap); //For robust!
}
◎研究:
typedef char * va_list;
# va_start _crt_va_start
# va_arg _crt_va_arg
# va_end _crt_va_end
# _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
# _crt_va_arg(ap,t) ( *(t *)((ap _INTSIZEOF(t)) - _INTSIZEOF(t)) )
# _crt_va_end(ap) ( ap = (va_list)0 )
va_list argptr;
C语言是从右向左压入堆栈,va_start后
按定义宏运算_ADDRESSOF得到v所在地址然后这个
地址加上v大小则使ap指向第个可变参数如图:
栈底 高地址
| .......
| 返回地址
| .......
| 最后个参数
| ....
| 第个可变参数 <--va_start后ap指向
| 最后个固定参数
| 第个固定参数
栈顶 低地址
然后用va_arg取得类型t可变参数值, 先是让ap指向下个参数:
ap _INTSIZEOF(t)然后在减去_INTSIZEOF(t)使得表达式结果为
ap的前值即当前需要得到参数地址强制转换成指向此参数
类型指针然后用*取值
最后用va_end(ap)给ap化保持健壮性
example:(chenguiming)
# <stdio.h>
# <ctype.h>
#<stdlib.h>
# <stdarg.h>
average( first, ... ) //变参数,C里也有
{
count=0,i=first,sum=0;
va_list maker; //va_list 类型数据可以保存所有参数,做为个列表样保存
va_start(maker,first); //设置列表起始位置
while(i!=-1)
{
sumi;
count;
i=va_arg(maker,);//返回maker列表当前值,并指向列表下个位置
}
sum/count;
}
void (void)
{
prf( "Average is: %d\n", average( 2, 3, 4,4, -1 ) );
}
Linux下stdarg.h
#ndef _STDARG_H
# _STDARG_H
typedef char *va_list; /* 定义va_list 是个指针类型*/
/* Amount of space required in an argument list for an arg of type TYPE.
TYPE may alternatively be an expression whose type is used. */
/* 下面给出了类型为TYPE arg 参数列表所要求空间容量
TYPE 也可以是使用该类型个表达式 */
// 下面这句定义了取整后TYPE 类型字节长度值是 长度(4)倍数
# __va_rounded_size(TYPE) \
((( (TYPE) + () - 1) / ()) * ())
// 下面这个(用宏实现)使AP 指向传给可变参数表第个参数
// 在第次va_arg 或va_end 的前必须首先该
// 17 行上__builtin_saveregs是在gcc 库libgcc2.c 中定义用于保存寄存器
// 它介绍说明可参见gcc 手册章节“Target Description Macros”中
// “Implementing the Varargs Macros”小节
#ndef __sparc__
# va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#
# va_start(AP, LASTARG) \
(__builtin_saveregs , \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#end
// 下面该宏用于被完成次正常返回va_end 可以修改AP 使其在重新
// va_start 的前不能被使用va_end 必须在va_arg 读完所有参数后再被
void va_end (va_list); /* Defined in gnulib *//* 在gnulib 中定义 */
# va_end(AP)
// 下面该宏用于扩展表达式使其和下个被传递参数具有相同类型和值
// 对于缺省值va_arg 可以用、无符号和浮点类型
// 在第次使用va_arg 时它返回表中第个参数后续每次都将返回表中
// 下个参数这是通过先访问AP然后把它增加以指向下项来实现
// va_arg 使用TYPE 来完成访问和定位下项每次va_arg它就修改AP 以指示
// 表中下参数
# va_arg(AP, TYPE) \
(AP __va_rounded_size (TYPE), \
*((TYPE *) (AP - __va_rounded_size (TYPE))))
#end /* _STDARG_H */
最新评论