可變參數列表(va_list,va_arg,va_copy,va_start,va_end)

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指向 
   | 函數最後一個固定參數
   | 函數第一個固定參數 
   棧頂 低地址
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章