可變參數的產生:首先看一段簡單求平均數代碼:
int average(int num,int v1,int v2,int v3,int v4)
{
return (v1+v2+v3+v4)/num;
}
#include <stdio.h>
int main()
{
int ret=average(4,1,4,5,6);
printf("%d\n",ret);
return 0;
}
此代碼中求平均值函數中有5個形參,在傳參過程中average(4,1,4,5,6)也傳了5個實參才能得出正確結果,也只能限定5個參數,在VS2010中,若調用函數實參個數小於形參個數或者大於形參個數編譯器會直接報錯,如:
所以這個程序是不可移植的,所以我們需要一種機制,它能夠以一種良好定義的方法訪問數量未定的參數列表,所以由此產生可變參數列表來實現這一功能。
可變參數列表是通過宏來實現的,定義與stdarg.h頭文件中,如下內容:
_INTSIZEOF(n)宏算出參數n類型的字節大小;
_ADDRESSOF(v)得出v的地址;
在_crt_va_arg(ap,t)中,ap先+=t類型大小,即ap值已經改變指向下一個,在減去t類型大小,並*引用最後得到上一個參數的值,最後這個宏就爲上一個參數的值,ap值也已經改變;
va_list爲一個typedef的char*類型,將以上程序使用可變參數列表實現:
#include <stdarg.h>
#include <stdio.h>
float Average(int n_values,...)//省略號代表可變參數部分
{
int i=0;
float sum=0;
//定義一個va_list(即char*類型)變量var_arg
va_list var_arg;
//調用va_start宏初始化變量var_arg使它指向可變參數部分的第一個參數
va_start(var_arg,n_values);
for(i=0;i<n_values;++i)
{
//調用va_arg返回當前可變參數的值,並使變量var_arg指向下一個可變參數
sum+=va_arg(var_arg,int);
}
//調用va_end將變量var_arg賦空
va_end(var_arg);
return sum/n_values;
}
int main()
{
float ret=Average(5,2,4,6,7,4);
printf("%lf\n",ret);
system("pause");
return 0;
}
即由此可得出和注意項爲:
1.va_start兩個參數,第一個爲va_list變量,第二個爲省略號前最後一個有名字的參數,這樣纔可以通過其地址和類型大小算出可變參數部分的第一個參數地址,來初始化va_list變量;
2.va_arg兩個參數,第一個爲va_list變量,第二個爲下一個可變參數的類型,從而算出當前參數的值和下一個可變參數的地址賦予va_list變量;
3.va_end一個參數爲va_list變量,使它指向NULL,不成爲野指針。