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

在stdarg.h文件中有如下几个宏定义:

[cpp] view plain copy
  1. #include <vadefs.h>

  2. #define va_start _crt_va_start

  3. #define va_arg _crt_va_arg

  4. #define va_end _crt_va_end

  5. #endif  /* _INC_STDARG */


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

[cpp] view plain copy
  1. #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )

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

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

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


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

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

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


      最后一个参数


  倒数第二个参数


  ...


  第一个参数


  函数返回地址


  函数代码段


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

[cpp] view plain copy
  1. #include<stdio.h>

  2. #include<stdlib.h>

  3. #include<stdarg.h>

  4. /*功能:可变参数求和

  5. *参数:numCount参数个数 ...可变求和参数

  6. *返回值:参数相加的和

  7. */

  8. int sum(int numCount,...)  

  9. {  

  10. int result = 0;     //计算结果

  11. va_list ap;         //初始化指向可变参数列表的指针(typedef char* va_list)

  12.    va_start(ap,numCount);          //将第一个可变参数的地址付给ap,即ap指向可变参数列表的开始

  13. for(int i = 0;i<numCount;i++)  

  14.        result += va_arg(ap,int);   //得到第一个可变参数的值,并且ap指针上移一个_INTSIZEOF(int),即指向下一个可变参数的地址.

  15.    va_end(ap);                     //置空ap,即ap=(void *)0;

  16. return result;  

  17. }  

  18. int main(void)  

  19. {  

  20.    printf("20+15+3+8=%d\n",sum(4,20,15,3,8));  

  21.    system("pause");  

  22. return 0;  

  23. }  


你可能感兴趣的:(c,可变参数函数)