va_list 、va_start、 va_arg、 va_end 使用說明【轉】
- 2019 年 10 月 11 日
- 筆記
轉自:https://blog.csdn.net/f110300641/article/details/83822290
在ANSI C中,這些宏的定義位於stdarg.h中:
typedef char *va_list;
va_start宏,獲取可變參數列表的第一個參數的地址(list是類型為va_list的指針,param1是可變參數最左邊的參數):
#define va_start(list,param1) ( list = (va_list)¶m1+ sizeof(param1) )
va_arg宏,獲取可變參數的當前參數,返回指定類型並將指針指向下一參數(mode參數描述了當前參數的類型):
#define va_arg(list,mode) ( (mode *) ( list += sizeof(mode) ) )[-1]
va_end宏,清空va_list可變參數列表:
#define va_end(list) ( list = (va_list)0 )
註:以上sizeof()只是為了說明工作原理,實際實現中,增加的位元組數需保證為為int的整數倍
如:#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。
- #include <stdio.h>
- #include <stdarg.h>
- void var_test(char *format, …)
- {
- va_list list;
- va_start(list,format);
- char *ch;
- while(1)
- {
- ch = va_arg(list, char *);
- if(strcmp(ch,"") == 0)
- {
- printf("n");
- break;
- }
- printf("%s ",ch);
- }
- va_end(list);
- }
- int main()
- {
- var_test("test","this","is","a","test","");
- return 0;
- }
附:可變參數應用實例
1.printf實現
- #include <stdarg.h>
- int printf(char *format, …)
- {
- va_list ap;
- int n;
- va_start(ap, format);
- n = vprintf(format, ap);
- va_end(ap);
- return n;
- }
2.訂製錯誤列印函數error
- #include <stdio.h>
- #include <stdarg.h>
- void error(char *format, …)
- {
- va_list ap;
- va_start(ap, format);
- fprintf(stderr, "Error: ");
- vfprintf(stderr, format, ap);
- va_end(ap);
- fprintf(stderr, "n");
- return;
【作者】張昺華
【出處】http://www.cnblogs.com/sky-heaven/