/********************************************************************
purpose: 可变参测试
author: dotlive
*********************************************************************/
#include <stdio.h>
#include <stdarg.h>
const int INT_TYPE = 100000;
const int STR_TYPE = 100001;
const int CHAR_TYPE = 100002;
const int LONG_TYPE = 100003;
const int FLOAT_TYPE = 100004;
const int DOUBLE_TYPE = 100005;
//测试va_start,va_arg的使用方法,函数参数在堆栈中的地址分布情况
void arg_test(int i, ...);
//第一个参数定义可选参数个数,用于循环取初参数内容
void arg_cnt(int cnt, ...);
//可变参数采用arg_type,arg_value...的形式传递,以处理不同的可变参数类型
void arg_type(int cnt, ...);
int main(int argc, char *argv[])
{
int int_size = _INTSIZEOF(int);
printf("int_size = %d\n", int_size);
printf("\nThis is arg_test's result:\n");
arg_test(0, 4);
printf("\nThis is arg_cnt's result:\n");
arg_cnt(4, 1, 2, 3 ,4);
printf("\nThis is arg_type's result:\n");
arg_type(2, INT_TYPE,222/*arg1*/, STR_TYPE,"ok,hello world!"/*arg2*/);
printf("\n");
return 0;
}
void arg_test(int i, ...)
{
int j = 0;
va_list arg_ptr;
va_start(arg_ptr, i);
//打印参数i在堆栈中的地址
printf("&i = %p\n", &i);
//打印va_start之后arg_ptr地址。应该比参数i的地址高sizeof(int)个字节, 这时arg_ptr指向下一个参数的地址
printf("arg_ptr = %p\n", arg_ptr);
j = *((int*)arg_ptr);
printf("%d %d\n", i, j);
j = va_arg(arg_ptr, int);
//打印va_arg后arg_ptr的地址。应该比调用va_arg前高sizeof(int)个字节, 这时arg_ptr指向下一个参数的地址
printf("arg_ptr = %p\n", arg_ptr);
va_end(arg_ptr);
printf("%d %d\n", i, j);
}
void arg_cnt(int cnt, ...)
{
int i = 0;
int arg_cnt = cnt;
int value = 0;
va_list arg_ptr;
va_start(arg_ptr, cnt);
for(i = 0; i < arg_cnt; i++)
{
value = va_arg(arg_ptr,int);
printf("value%d = %d\n", i+1, value);
}
}
void arg_type(int cnt, ...)
{
int i = 0;
int arg_cnt = cnt;
int arg_type = 0;
int int_value = 0;
char *str_value = NULL;
va_list arg_ptr;
va_start(arg_ptr, cnt);
for(i = 0; i < arg_cnt; i++)
{
arg_type = va_arg(arg_ptr, int);
switch(arg_type)
{
case INT_TYPE:
int_value = va_arg(arg_ptr, int);
printf("value%d = %d\n", i+1, int_value);
break;
case STR_TYPE:
str_value = va_arg(arg_ptr, char*);
printf("value%d = %s\n", i+1, str_value);
break;
default:
break;
}
}
}
其中,在VC的库文件中有一个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) // 将指针置为无效