C/C++ 可變參數

爲了解決這些問題,我們首先要解釋cdecl調用約定(參見論調用約定),所有使用不定參數的函數必須是使用cdecl(全局函數)或者this call(類成員函數)調用約定。該約定對於參數傳遞規定如下:

  1. 參數從右向左入棧(也就是如果你調用f(a,b,c),則c先入棧,然後是b,最後是a入棧)
  2. 調用者負責清理堆棧

在設計具有不定參數列表的函數的時候,我們有兩種方法來確定到底多少參數會被傳遞進來。

方法1是在類型固定的參數中指明後面有多少個參數以及他們的類型。printf就是採用的這種方法,它的format參數指明後面每個參數的類型。

方法2是指定一個結束參數。這種情況一般是不定參數擁有同樣的類型,我們可以指定一個特定的值來表示參數列表結束。

  1. #include "stdarg.h"  
  2. using namespace std;  
  3.   
  4. int sum(int count, ...)  
  5. {  
  6.     int sum_value=0;  
  7.   
  8.     va_list args;  
  9.     va_start(args,count);  
  10.     while(count--)  
  11.     {  
  12.         sum_value+=va_arg(args,int);  
  13.     }  
  14.     va_end(args);  
  15.   
  16.     return sum_value;  
  17. }  
  18.   
  19. int _tmain(int argc, _TCHAR* argv[])  
  20. {  
  21.     cout<<sum(5,1,2,3,4,5);//輸出15  
  22. }  


在vc6,va_start函數定義爲:

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )

其中_INTSIZEOF(n)計算比n大的sizeof(int)的最小倍數,如果n=101,則_INTSIZEOF(n)爲104。

va_start執行完畢後,ap指向變量v後第一個4字節對齊的地址。例如,v的地址爲0x123456, v的大小爲13,則v後面的下一個與字邊界對齊的地址爲0x123456+0x0D=0x123463再調整爲與4字節對齊的下一個地址,也就是 0x123464.

va_arg函數定義爲:

#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

分析與va_start一樣,它的結果是使ap指向當前變量的下一個變量。

這樣,我們只要在開始時使用va_start把不定參數列表賦值給ap,然後依次用va_arg獲得不同參數即可。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章