实现原理和理论依据:
函数参数传递的时候,参数是线性的存储在内存中的,因此,如果知道参数存放的起始位置和结束位置,和参数的类型,那么就可以得到需要的所有参数.
关于不定参数头文件stdarg.h中的几个宏定义(每一个颜色板块为一个宏定义及其解释):
va_list:
#ifndef _VA_LIST_DEFINED
#ifdef _M_ALPHA
typedef struct {
char *a0; /* pointer to first homed integer argument */
int offset; /* byte offset of next parameter */
} va_list;
#else
typedef char * va_list;
#endif
#define _VA_LIST_DEFINED
#endif
其中a0或者va_list是第一个参数的地址,offset是从第一个参数到第二个参数的内存地址偏移量,由参数的类型占用内存的空间决定.
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
得到参数n的尺寸,相当与sizeof(n),为了兼容性写成了如上的表达式.
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
其中ap是一个va_list型的参数列表指针变量,v是参数表中的第一个参数的名字.作用是初始化参数表,并让参数表指针ap指向参数列表的第二个参数开始地址(根据以上宏定义的表达式得知).
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
根据参数类型移动参数表指针ap,使之返回下一个参数的值,参数的类型由第二个参数t指定(分析以上宏定义表达式).
#define va_end(ap) ( ap = (va_list)0 )
结束参数传递,做清理工作,即让参数表指针清空.
#include < stdio.h>
#include < string.h>
#include < stdarg.h>
#include
int sum(int first,...)///* 函数原型声明,至少需要一个确定的参数,注意括号内的省略号 */
{
va_list ap;//定义保存函数参数的结构
va_start (ap,first);//初始化参数表,并让参数表指针ap指向参数列表的第二个参数开始地址
int sum=first;
while (va_arg(ap,int))//以0结束
{
sum+=va_arg(ap,int);//根据参数类型移动参数表指针ap,使之返回下一个参数的值
}
va_end(ap);
return sum;
}
int main()
{
printf ("%d\n",sum(1,2,3,4,5,6,7,0));
system("pause");
return 0;
}
运用优劣参考 链接