关于C中函数的可变参数va_list...

来源:互联网 发布:软件开发班 编辑:程序博客网 时间:2024/05/04 12:28
 

关于C中函数的可变参数va_list...

分类: C/C++ 4781人阅读 评论(0) 收藏 举报
clistunixinteger平台编译器

先来个简单的例子:
#include <stdio.h>
#include <stdarg.h>
int sum(int num,...);
int sum(int num,...)
{
 int result = 0;
 va_list argptr;
 va_start(argptr, num);
 while(num--)
 {
  //result += va_arg(argptr, int);
  printf("%s ",va_arg(argptr, char *));
 }
 va_end(argptr);
 return result;
}
int main()
{
 sum(3, "hello", "world", "!");       // output: hello world !
 //printf("%d/n", sum(4, 1, 2, 3 ,4));
 //printf("%d/n", sum(2, 1, 2, 3 ,4));
 return 0;
}

       可变参数中个数不定可是传入的是一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。
       可变参数是由宏实现的,但是由于硬件平台的不同,编译器的不同,宏的定义也不相同,下面是VC6.0中x86平台的定义:

typedef char * va_list;     // TC中定义为void*
#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 )

      C语言的函数形参是从右向左压入堆栈的,以保证栈顶是第一个参数,而且x86平台内存分配顺序是从高地址到低地址。因此似函数fun(int var1,int var2,...,int varN)内存分配大致上是这样的:(可变参数在中间)
栈区:
|栈顶             低地址
|第一个参数var1                  <-- &v
|第二个参数var2                  <-- va_start(ap,v)后ap指向地址       
|...
|函数的最后varN
|...
|函数的返回地址
|...
|栈底    高地址
va_start(ap,v);后ap = (va_list)&v + _INTSIZEOF(v)指向第二个参数地址
调用va_arg(ap,t)  ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )取出当前ap指针所指的值,并使ap指向下一个参数

不过被定义为宏的东西用起来要小心,我现在用不着va_list,不过先了解点皮毛也好。

下面是msdn中的例子:

#include <stdio.h>
#define ANSI            /* Comment out for UNIX version     */
#ifdef ANSI             /* ANSI compatible version          */
#include <stdarg.h>
int average( int first, ... );
#else                   /* UNIX compatible version          */
#include <varargs.h>
int average( va_list );
#endif

void main( void )
{
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d/n", average( 2, 3, 4, -1 ) );

   /* Call with 4 integers. */
   printf( "Average is: %d/n", average( 5, 7, 9, 11, -1 ) );

   /* Call with just -1 terminator. */
   printf( "Average is: %d/n", average( -1 ) );
}

/* Returns the average of a variable list of integers. */
#ifdef ANSI             /* ANSI compatible version    */
int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#else       /* UNIX compatible version must use old-style definition.  */
int average( va_alist )
va_dcl
{
   int i, count, sum;
   va_list marker;

   va_start( marker );            /* Initialize variable arguments. */
   for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
      sum += i;
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#endif


在来一个简单的例子:
#include <stdio.h>
#include <stdarg.h>

void print(char *format,...);    //自定义输出格式
void print(char *format,...)
{
 va_list argptr;
 va_start(argptr, format);
 while(*format != '/0')
 {
  switch(*(format++))
  {
  case 's': printf("%s ", va_arg(argptr, char *)); break; 
  case 'i': printf("%d ", va_arg(argptr, int)); break; 
  case 'c': printf("%c ", va_arg(argptr, char)); break; 
  case 'f': printf("%.1f/n", va_arg(argptr, double)); break; 
  default: break;
  }
 }
 va_end(argptr);
}
int main()
{
 print("sicft","laomou",24,'M',120.0);    // 输出格式依次为 string, integer, char, float
 return 0;
}

原创粉丝点击