轉自:https://blog.csdn.net/f110300641/article/details/83822290linux
在ANSI C中,這些宏的定義位於stdarg.h中:函數
typedef char *va_list;佈局
va_start宏,獲取可變參數列表的第一個參數的地址(list是類型爲va_list的指針,param1是可變參數最左邊的參數):ui
#define va_start(list,param1) ( list = (va_list)¶m1+ sizeof(param1) )this
va_arg宏,獲取可變參數的當前參數,返回指定類型並將指針指向下一參數(mode參數描述了當前參數的類型):spa
#define va_arg(list,mode) ( (mode *) ( list += sizeof(mode) ) )[-1].net
va_end宏,清空va_list可變參數列表:3d
#define va_end(list) ( list = (va_list)0 )指針
注:以上sizeof()只是爲了說明工做原理,實際實現中,增長的字節數需保證爲爲int的整數倍code
如:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
爲了理解這些宏的做用,咱們必須先搞清楚:C語言中函數參數的內存佈局。首先,函數參數是存儲在棧中的,函數參數從右往左依次入棧。
如下面函數爲討論對象:
void test(char *para1,char *param2,char *param3, char *param4) { va_list list; ...... return; }
在linux中,棧由高地址往低地址生長,調用test函數時,其參數入棧狀況以下:
當調用va_start(list,param1) 時:list指針指向狀況對應下圖:
最複雜的宏是va_arg。
附:可變參數應用實例
1.printf實現
2.定製錯誤打印函數error