可变参数传递方法
---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里的一个例子。
- /* VA.C: The program below illustrates passing a variable
- * number of arguments using the following macros:
- * va_start va_arg va_end
- * va_list va_dcl (UNIX only)
- */
- #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
通过上面的例子可以清楚知道怎么传递可变参数了。
(2)方法2:利用参数入栈原理
在现有的32位的机器上,一般通过将参数按照由低地址到高地址的顺序依次入栈实现传递,因此把第一参数的指针依次增加,就可以得到后面的参数了。例如:
- struct s1
- {
- int a;
- char b;
- };
- struct s2
- {
- int a;
- };
- void function (struct s1 a, ...)
- {
- struct s1* pa = &a;
- printf("%d, %c/n", pa->a, pa->b);
- ++pa;
- printf("%d, %c/n", pa->a, pa->b);
- ++pa;
- printf("%d/n", (struct s2*)pa->a); //强制转换为struct s2类型
- }
- void main( void )
- {
- struct s1 a1 = {1, 'A'};
- struct s1 a2 = {2, 'B'};
- struct s2 a3 = {10};
- function(a1, a2, a3); //a3的类型不同于a1, a2
- return;
- }
用这种方法传递可变参数非常简单。
(3)方法3:用数组传参
- void function(Type a[])
- {
- ...
- a[0];
- a[1];
- ...
- }
这种方法就不唠叨了,相信地球人都知道。