可变参数传递的方法

 可变参数传递方法
        ---written by andyhua

 

       有时候,我们写函数的时候,可能遇到参数数量不确定的情况,这样的函数例如C的printf打印函数。你可以使用printf("some string"), 也可以使用printf("%d", aintvalue)。是不是C的库里包含了不同定义的printf函数呢?答案肯定是否定的,因为C是不支持函数的重载的。每个函数只能由一个版本。那么是如何实现类似这种可变参数传递的函数呢?在这讲三种方法。

(1)方法1:使用va_list
          涉及到如下变量和函数(摘自msdn):
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
void va_start( va_list arg_ptr );   (UNIX version)
void va_start( va_list arg_ptr, prev_param );   (ANSI version)
         参数含义:
type:参数类型
arg_ptr:指向参数列表的指针
prev_param:第一个参数的类型

         下面采用msdn里的一个例子。

  1. /* VA.C: The program below illustrates passing a variable
  2.  * number of arguments using the following macros:
  3.  *      va_start            va_arg              va_end
  4.  *      va_list             va_dcl (UNIX only)
  5.  */
  6. #include <stdio.h>
  7. #define ANSI            /* Comment out for UNIX version     */
  8. #ifdef ANSI             /* ANSI compatible version          */
  9. #include <stdarg.h>
  10. int average( int first, ... );
  11. #else                   /* UNIX compatible version          */
  12. #include <varargs.h>
  13. int average( va_list );
  14. #endif
  15. void main( void )
  16. {
  17.    /* Call with 3 integers (-1 is used as terminator). */
  18.    printf( "Average is: %d/n", average( 2, 3, 4, -1 ) );
  19.    /* Call with 4 integers. */
  20.    printf( "Average is: %d/n", average( 5, 7, 9, 11, -1 ) );
  21.    /* Call with just -1 terminator. */
  22.    printf( "Average is: %d/n", average( -1 ) );
  23. }
  24. /* Returns the average of a variable list of integers. */
  25. #ifdef ANSI             /* ANSI compatible version    */
  26. int average( int first, ... )
  27. {
  28.    int count = 0, sum = 0, i = first;
  29.    va_list marker;
  30.    va_start( marker, first );     /* Initialize variable arguments. */
  31.    while( i != -1 )
  32.    {
  33.       sum += i;
  34.       count++;
  35.       i = va_arg( marker, int);
  36.    }
  37.    va_end( marker );              /* Reset variable arguments.      */
  38.    return( sum ? (sum / count) : 0 );
  39. }
  40. #else       /* UNIX compatible version must use old-style definition.  */
  41. int average( va_alist )
  42. va_dcl
  43. {
  44.    int i, count, sum;
  45.    va_list marker;
  46.    va_start( marker );            /* Initialize variable arguments. */
  47.    for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
  48.       sum += i;
  49.    va_end( marker );              /* Reset variable arguments.      */
  50.    return( sum ? (sum / count) : 0 );
  51. }
  52. #endif

          通过上面的例子可以清楚知道怎么传递可变参数了。

(2)方法2:利用参数入栈原理  
         在现有的32位的机器上,一般通过将参数按照由低地址到高地址的顺序依次入栈实现传递,因此把第一参数的指针依次增加,就可以得到后面的参数了。例如:

  1. struct s1 
  2. {
  3.     int a;
  4.     char b;
  5. };
  6. struct s2 
  7. {
  8.     int a;
  9. };
  10. void function (struct s1 a, ...) 
  11. {
  12.     struct s1*  pa = &a;
  13.     printf("%d, %c/n", pa->a, pa->b);
  14.     ++pa;
  15.     printf("%d, %c/n", pa->a, pa->b);
  16.     ++pa;
  17.     printf("%d/n", (struct s2*)pa->a);  //强制转换为struct s2类型
  18. }
  19. void main( void )
  20. {
  21.     struct s1 a1 = {1, 'A'};
  22.     struct s1 a2 = {2, 'B'};
  23.     struct s2 a3 = {10};
  24.     function(a1, a2, a3); //a3的类型不同于a1, a2
  25.     return;
  26. }

        用这种方法传递可变参数非常简单。


(3)方法3:用数组传参

 

  1. void   function(Type a[])   
  2. {   
  3.   ...   
  4.   a[0];    
  5.   a[1];   
  6.   ...   
  7. }

这种方法就不唠叨了,相信地球人都知道。       

展开阅读全文

没有更多推荐了,返回首页