实现原理和理论依据:
函数参数传递的时候,参数是线性的存储在内存中的,因此,如果知道参数存放的起始位置和结束位置,和参数的类型,那么就可以得到需要的所有参数.
关于不定参数头文件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 <stdlib.h> 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; }
运用优劣参考 链接