/********************************************************************
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) //將指針置爲無效