炽翼铁冰's Blog

Trying to become a programmer
动态SQL语句写法

C不定参数写法

炽翼铁冰 posted @ 2009年11月20日 07:15 in C(转载) , 3238 阅读

由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦;即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,有些人采用指针参数来解决问题.下面就c语言中处理不定参数数目的问题进行讨论.

在stdarg.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 )                            // 将指针置为无效

在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的.
总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段.
堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:
最后一个参数
倒数第二个参数
...
第一个参数
函数返回地址
函数代码段 (这是在一篇文章中对函数堆栈地址的解释,感觉解释得还算通俗易懂)

主要函数介绍:

va_start使argp指向第一个可选参数。va_arg返回参数列表中的当前参数并使argp指向参数列表中的下一个参数。va_end把argp指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。

示例代码:

 

 

#include 〈stdio.h〉
#include 〈string.h〉
#include 〈stdarg.h〉
  
int demo( char, ... );
void main( void )
{
   demo("DEMO", "This", "is", "a", "demo!", "");
}
  
int demo( char msg, ... )
{

   va_list argp;
   int argno = 0;
   char para;

  
   va_start( argp, msg );
   while (1)
    {
      para = va_arg( argp, char);
      if ( strcmp( para, "") == 0 )
            break;
       printf("Parameter #%d is: %s\n", argno, para);
       argno++;
   }
   va_end( argp );
  
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter