摘要
C語言中有壹個長度不確定的參數,比如“…”,主要用在參數個數不確定的函數中,printf函數就是我們想到的最簡單的例子。
原型:
int printf( const char *format [,argument]...);
使用案例:
printf("享受每壹天!\ \ n ");
printf("值是%d!\\n ",值);
這個可變參數可以說是C語言的壹個難點,這裏會由幾個問題引發壹些分析。
註意:在C++中,有壹個函數重載可以用來區分不同函數參數的調用,但是仍然不能表示任意數量的函數參數。
問:printf的實現
請問printf函數怎麽實現,裏面的可變參數怎麽處理?答案和分析:
頭文件
typedef char * va _ list
# define va _ start(list)list =(char *)& amp;列表
#定義va_end(列表)
#define va_arg(list,mode)\\
((mode *)(list+= sizeof(mode)))[-1]
自己實現printf:
# include & ltstdarg.h & gt
int printf(char*格式,…)
{
va _ list ap
va_start(ap,格式);
int n = vprintf(format,AP);
va _ end(AP);
返回n;
}
問題:運行時確定的參數。
有沒有什麽方法可以寫出壹個函數,它的參數可以在運行時確定?
答案和分析:
目前還沒有“正常”的解決方法,但是有壹個獨壹無二的偏方,因為有壹個函數在這方面給我們做了壹個榜樣,就是main(),它的原型是:
int main(int argc,char * argv[]);
該函數的參數是argc和argv。
往深裏想,“參數形式只能在運行時確定”,也就是說從聲明中看不到被接受的參數,也就是參數根本沒有固定的形式。常見的方式是妳可以決定
意思是空虛
*類型參數,用它指向實際的參數區,然後根據需要在函數中任意解釋它們的含義。這是argv在主函數中的意義,而argc是用來表現現實的。
參數的個數,這為我們使用提供了進壹步的方便,當然這個參數不是必須的。
雖然參數沒有固定的形式,但我們必須分析函數中參數的含義。所以自然會有壹個要求,就是調用者和被調用者要在參數區內容的格式、大小、有效性等方面達成壹致,否則不同意就慘了。
問題:可變長度參數的傳輸
有時,需要編寫壹個函數,並將其變長參數直接傳遞給另壹個函數。這個要求能實現嗎?
答案和分析:
目前妳沒有辦法直接做到這壹點,但是我們可以繞道。首先我們將被調用函數的參數定義為va_list類型,同時在調用函數中將變長參數列表轉換為va_list,這樣就可以傳遞變長參數了。請看以下內容:
void subfunc (char *fmt,va_list argp)
{
...
arg = va_arg (fmt,argp);/*從argp中逐個取出需要的參數*/
...
}
void mainfunc (char *fmt,...)
{
va _ list argp
va_start (argp,fmt);/*將變長參數轉換為va_list */
subfunc (fmt,argp);/*將va_list傳遞給子函數*/
va _ end(argp);
...
}
問題:變長參數的類型是函數指針。
我想用va_arg從變長參數中提取類型為函數指針的參數,但結果總是不正確。為什麽?
答案和分析:
這和va_arg的實現有關。va_arg的簡單演示版本實現如下:
#define va_arg(argp,type) \\
(*(type *)(((argp)+= sizeof(type))-sizeof(type)))
其中argp的類型是char *。
如果妳想用va_arg從變量參數列表中提取函數指針類型的參數,例如
Int (*),那麽va_arg(argp,int (*))擴展為:
(*(int(*)()*)(((argp)+= sizeof(int(*))-sizeof(int(*))))
顯然,(int (*)() *)是沒有意義的。
解決這個問題的方法是用typedef將函數指針定義為獨立的數據類型,例如:
typedef int(* func ptr)();
此時,調用va_arg(argp,funcptr)將擴展為:
(*(funcptr *)(((argp)+= sizeof(funcptr))-sizeof(funcptr)))
這樣就可以通過編譯檢查了。
問題:獲取可變長度參數
有這樣壹個帶有可變長度參數的函數,其中使用了以下代碼來獲取float類型的參數:
va_arg (argp,float);
這樣做可以嗎?
答案和分析:
妳不能。在可變長度參數中,應用了“加寬”原則。即float類型擴展為double;char,
Short擴展為int。因此,如果要去變長參數float,需要使用va_arg(argp,
雙倍).對於char和short類型,使用va_arg(argp,int)。
問題:定義可變長度參數的限制
為什麽我的編譯器不允許我定義以下函數,也就是變長參數,但是沒有固定參數?
int f(...)
{
...
}
答案和分析:
妳不能。這是ANSI C所要求的,您必須定義至少壹個固定參數。
這個參數將被傳遞給va_start(),然後va_arg()和va_end()將被用來確定實際調用過程中所有變長參數的類型和值。