您的位置:首页 > 其它

C可变参数详解及其函数设计

2012-10-06 18:31 337 查看
在stdarg.h文件中有如下几个宏定义:

#include <vadefs.h>

#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end

#endif  /* _INC_STDARG */


其定义在vadefs.h中分别为:

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址

#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效


在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的.

总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段.

堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:

最后一个参数

  倒数第二个参数

  ...

  第一个参数

  函数返回地址

  函数代码段

代码示例:这里是一个可变参数的加法函数

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>

/*功能:可变参数求和
*参数:numCount参数个数 ...可变求和参数
*返回值:参数相加的和
*/
int sum(int numCount,...)
{
int result = 0;     //计算结果
va_list ap;         //初始化指向可变参数列表的指针(typedef char* va_list)

va_start(ap,numCount);          //将第一个可变参数的地址付给ap,即ap指向可变参数列表的开始
for(int i = 0;i<numCount;i++)
result += va_arg(ap,int);	//得到第一个可变参数的值,并且ap指针上移一个_INTSIZEOF(int),即指向下一个可变参数的地址.
va_end(ap);                     //置空ap,即ap=(void *)0;

return result;
}

int main(void)
{
printf("20+15+3+8=%d\n",sum(4,20,15,3,8));

system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: