可變引數的函式,即函式的引數個數和引數型別不完全確定的函式。這類函式最常見的就是printf、scanf函式。在c/c++中,為了通知編譯器函式有可變引數,必須以三個點結束該函式的宣告。例如:
//printf函式的宣告
int printf(const char * _format, ...);
//scanf函式宣告
int scanf(const char * _format, ...);
//自定義變長引數函式func的宣告
int func(int a, int b, ...);
上面func函式的宣告指出該函式至少有兩個整型引數和緊隨其後的0個或多個型別未知的引數。在c/c++中,任何使用變長引數宣告的函式都必須至少有乙個指定的引數(又稱強制引數),即至少有乙個引數的型別是已知的,而不能用三個點省略所有引數的指定,且已知的指定引數必須宣告在函式最左端。
變長引數函式的實現關鍵在於怎麼使用引數,指定了的引數好說,直接使用指定的引數名稱訪問,但未指定的引數呢?我們知道函式呼叫過程中引數傳遞是通過棧來實現的,一般呼叫都是從右至左的順序壓引數入棧,因此引數與引數之間是相鄰的,知道前乙個引數的型別及位址,根據後乙個引數的型別就可以獲取後乙個引數的內容。對於變長引數函式,結合一定的條件,我們可以根據最後乙個指定引數獲取之後的省略引數內容。例如,對於函式func,我們知道了引數b的位址及型別,就可知道第乙個可變引數的棧位址(如果有的話),如果知道第乙個可變引數的型別,就可知道第乙個可變引數的內容和第二個可變引數的位址(如果有的話)。以此類推,可以實現對可變引數函式的所有引數的訪問。
那麼,要怎麼指定上訴的「一定的條件」呢?最簡單的方法就像printf等函式一樣,使用格式化佔位符。分析格式化字串引數,通過事先定義好的格式化佔位符可知可變引數的型別及個數,從而獲取各個引數內容。一般對於可變引數型別相同的函式也可直接在強制引數中指定可變引數的個數和型別,這樣也能獲取各個引數的內容。
無論哪種,都涉及對棧位址偏移的操作。結合棧儲存模式和系統資料型別的字長,我們可根據可變引數的型別很容易得到棧位址的偏移量。
//可變引數標準巨集標頭檔案
#include "stdarg.h"
//申明va_list資料型別變數pvar,該變數訪問變長引數列表中的引數。
va_list pvar;
//巨集va_start初始化變長引數列表。pvar是va_list型變數,記載列表中的引數資訊。
//parmn是省略號"..."前的乙個引數名,va_start根據此引數,判斷引數列表的起始位置。
va_start(pvar, parmn);
//獲取變長引數列表中引數的值。pvar是va_list型變數,type為引數值的型別,也是巨集va_arg返回數值的型別。
//巨集va_arg執行完畢後自動更改物件pvar,將其指向下乙個引數。需要注意的是通過...傳進來的引數若實參為
//char、float型,其通過...會公升為int、double型,所以va_arg的type需為int、double型
va_arg(pvar, type);
//關閉本次對變長引數列表的訪問。
va_end(pvar);
如下圖所示,為後面示例中format函式的棧示意圖(注意高位址是棧底)
//va_list args; //定義乙個可變引數列表
//va_start(args,arg); //初始化args指向強制引數arg的下乙個引數
//va_arg(args,type); //獲取當前引數內容並將args指向下乙個引數
//va_end(args); //釋放args
#include
#include
#include
#define maxbuf 512
/* * 功能:利用變長引數函式格式化字串
* @count:可變引數數量
* * 返回:求和結果
*/double sum(unsigned
int count, ...)
va_end(args); //釋放args
return sum;}/*
* 功能:利用變長引數函式格式化字串
* @format:未格式化前的字串
* * 返回:格式化後的字串
*/std::string format(const
char *format, ...)
/* * 功能:測試
* @count:強制引數
* * 返回:格式化後的字串
*/void ttt(int count, ...)
int main(void)
參考:
c 語言的可變參數列函式的設計
【c++基礎之二十】可變引數的函式
c++ 變長引數函式小結
C C 可變引數函式
標頭檔案 include 函式宣告 int add int count,函式定義 int add int count,函式呼叫 int main 邊長引數模板相當於乙個模板的遞迴展開模型,但是它不是遞迴的。使用的時候,要定義乙個 遞迴 的出口,然後定義一系列的操作,操作的是以 遞迴 的方式進行的。遞...
可變引數的c c 函式
最近在寫遊戲的時候看到書上寫了個virtual void displaytext int id,long x,long y,unsigned long color,char text,0 當我看到這個函式時,我和小夥伴們都驚呆啦,我的娘,這是神馬函式,還帶省略號的,難道是書上寫錯了?然後我抱著試試看...
C C 可變引數
函式 使用va list巨集組解決變參問題 1 首先定義va list型的變數,這個變數是指向引數的指標。2 然後用va start巨集初始化剛定義的va list變數,這個巨集的第二個引數是 第乙個可變引數的前乙個引數 3 再用va arg得到可變引數,第二個引數是 可變引數 的型別。4 最後用v...