采用ANSI标准形式时,参数个数可变的函数的原型声明是:
type funcname(type para1, type para2, ...)
这种形式至少需要一个普通的形式参数,后面的省略号不表示省略,而是函数原型的一部分。type是函数返回值和形式参数的类型。
不同的编译器,对这个可变长参数的实现不一样 ,gcc4.x中是采用内置函数的方法来实现。
接下来我们看看以下示例代码:
#include <stdarg.h>
#include <stdio.h>
int Sum (int, ...);
int main(void)
{
int num;
num = Sum(5, 1, 2, 3, 4);
printf("%d/n", num);
return 0;
}
int Sum (int n, ...)
{
int i = 0, j = 0;
va_list p; /*定义一个变量 ,保存函数参数列表的指针*/
va_start(p, n); /*用va_start宏初始化变量p,
va_start宏的第2个参数n,
是一个固定的参数,
必须是我们自己定义的变长函数的最后一个入栈的参数
也就是调用的时候参数列表里的第1个参数*/
for (j = 1; j < n; ++j) /* j从1开始,遍历所有可变参数 */
{
i += va_arg(p, int); /*va_arg取出当前的参数,
并认为取出的参数是一个整数(int) */
}
return i;
}
当我们调用Sum函数时,传递给Sum函数的参数列表的第一个参数n的值是5,
va_start 初始化 p使其指向第一个未命名的参数(n是有名字的参数) ,也就是1(第一个),
每次对 va_arg的调用,都将返回一个参数,并且把 p 指向下一个参数,
va_arg 用一个类型名来决定返回的参数是何种类型,以及在 var_arg的内部实现中决定移动多大的距离才到达下一个参数。
void test (int a, ...)
{
char *ap;
char ch;
char str[4];
short s;
int n;
ap = (char*)&a ;
ap += 4;
ch = *ap;
ap += 4;
memcpy(str, (char*)(*(unsigned *)ap), 4);
ap += 4;
s = *((short *)ap);
ap += 4;
n = *((int *)ap);
ap += 4;
printf("a: %d, ch: %c, str: %s, s: %d, n: %d/n", a, ch, str, s, n);
}
int main()
{
test(100, 'A', "ABC", 123, 87654);
return 0;
}
这个例子中参数们被放置在一个32位的数组中
参数int a是第一个参数,通过他的地址依次+32位即代码中的ap+=4就可以找到其他参数地址并转换成相应的类型
这种方式不灵活,不同的系统情况可能不同,所以最好用已经定义好的宏
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
void va_start( va_list arg_ptr );
void va_start( va_list arg_ptr, prev_param );