本文轉自:http://blog.csdn.net/costa100/article/details/5787068
va_list arg_ptr:定義一個指向個數可變的參數列表指針;
va_start(arg_ptr, argN):使參數列表指針arg_ptr指向函數參數列表中的第一個可選參數,說明:argN是位於第一個可選參數之前的固定參數,(或者說,最後一個固定參數;…之前的一個參數),函數參數列表中參數在內存中的順序與函數聲明時的順序是一致的。如果有一va函數的聲明是void va_test(char a, char b, char c, …),則它的固定參數依次是a,b,c,最後一個固定參數argN爲c,因此就是va_start(arg_ptr, c)。
va_arg(arg_ptr, type):返回參數列表中指針arg_ptr所指的參數,返回類型爲type,並使指針arg_ptr指向參數列表中下一個參數。
va_copy(dest, src):dest,src的類型都是va_list,va_copy()用於複製參數列表指針,將dest初始化爲src。
va_end(arg_ptr):清空參數列表,並置參數指針arg_ptr無效。說明:指針arg_ptr被置無效後,可以通過調用va_start()、va_copy()恢復arg_ptr。每次調用va_start() / va_copy()後,必須得有相應的va_end()與之匹配。參數指針可以在參數列表中隨意地來回移動,但必須在va_start() … va_end()之內。
◎用法:
func( Type para1, Type para2, Type para3, … )
{
/* Step 1 */
va_list ap;
va_start( ap, para3 ); //一定要“…”之前的那個參數
/* Step 2 */
//此時ap指向第一個可變參數
//調用va_arg取得裏面的值
Type xx = va_arg( ap, Type );
//Type一定要相同,如:
//char p = va_arg( ap, char );
//int i = va_arg( ap, int );
//如果有多個參數繼續調用va_arg
/* Step 3 */
va_end(ap); //For robust!
}
◎研究:
typedef char * va_list;
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
va_list argptr;
C語言的函數是從右向左壓入堆棧的,調用va_start後,
按定義的宏運算,_ADDRESSOF得到v所在的地址,然後這個
地址加上v的大小,則使ap指向第一個可變參數如圖:
棧底 高地址
| …….
| 函數返回地址
| …….
| 函數最後一個參數
| ….
| 函數第一個可變參數 <–va_start後ap指向
| 函數最後一個固定參數
| 函數第一個固定參數
棧頂 低地址