可變參函式,顧其名而思義,就是該函式的引數數目不固定,例如我們的格式化輸出函式
int printf(const char *fmt, ...)
這個函式的「…」引數就代表它是個可變參的函式。這個函式第乙個引數一定是乙個字串,通過字串中的「d%」,「%s」等等來對應後面的引數數量,這樣以來就可以正確解析函式的引數。
實現可變參函式,依賴於三個巨集和乙個資料型別
三個巨集分別是va_arg, va_end, va_start
乙個資料型別則是va_list
va_list 的 va是variable-argument(可變引數)。list則就是列表的意思,但它到底是什麼呢?
typedef
char *va_list;//linux核心中va_list的實現
原來,va_list就是乙個char *的資料型別。
va_start是乙個巨集定義,接收兩個引數
#define va_start(ap, a) //linux核心中巨集定義的原型在此
(void) ((ap) = (((char *) &(a)) + (_bnd (a,_aupbnd))))
第乙個引數ap,就是剛才提到的va_list 型別,第二個引數a,就是乙個確定的型別,也就是「…」的型別,它會將這些型別的位址放到va_list中,根據初始化a來初始化ap。
va_arg是乙個巨集定義,接收兩個引數
#define va_arg(ap, t) //linux核心中巨集定義的原型在此
(*(t *)(((ap) += (_bnd (t, _aupbnd))) - (_bnd (t,_adn bnd))))
ap 也是va_list型別, t是乙個型別。從引數列表中取出乙個引數,型別就是t
va_end是乙個巨集
#define va_end(ap) (ap = (va_list) null)
通過這個巨集,可以清楚的看到,將va_list型別的ap賦值為null。
通過va_start初始化引數列表(得到具體的引數個數),引數列表由va_list定義,然後使用va_arg從引數列表中取出引數並處理,最後呼叫va_end來清理引數列表。
格式化輸出printf()函式在linux核心中的原始碼:
int
printf(const
char *fmt, ...)
編寫乙個可變參的求和函式:
int
sum(int cnt,...)
C語言可變參函式的實現
函式是大多數程式語言都實現的程式設計要素,呼叫函式的實現原理就是 執行跳轉 引數傳遞。對於執行跳轉,所有的cpu都直接提供跳轉指令 對於引數傳遞,cpu會提供多種方式,最常見的方式就是利用棧來傳遞引數。c語言標準實現了函式呼叫,但是卻沒有限定實現細節,不同的c編譯器廠商可以根據底層硬體環境自行確定實...
可變參函式(my printf可變參函式的實現)
可變參函式 其引數列表的引數型別與個數可變,採用ansi標準形式時,引數個數可變的函式的原型宣告是 type funcname type para1,type para2,至少需要乙個普通的形式引數,後面的省略號不表示省略,而是函式原型的一部分,為引數佔位符,type是函式返回值和形式引數的型別 可...
可變參函式
int add int x,int main int add int x,int sum 0 char point char x for int i 0 iint add int x,可變參函式原型,該函式中帶有識別符號的引數 x記錄的是引數的個數,後面的數字是需要求和的數。x的作用是為了標誌出加數...