stdarg.h:函数参数不确定时用cstdarg(stdarg.h)



◎使用方法:
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 */


Tags:  函数的参数 函数参数 main函数的参数 stdarg.h

延伸阅读

最新评论

发表评论