什麼是變長引數?
所謂含有變長引數的函式是指該函式可以接受可變數目的形參。例如我們都非常熟悉的
printf,scanf等等。
2:變長引數如何實現?
首先來看下面這樣乙個例子:
#include
#include
#include
void demo(char *msg,...)
else
break;
para = va_arg(argp,char *);
}va_end(argp);
}int main()
實現這樣乙個函式要在內部使用va_list,va_start,va_arg,va_end,這些都是定義在
stdarg.h中的巨集。
va_list是定義了乙個儲存函式引數的資料結構。
va_start(argp,msg)是將argp指向第乙個可變引數,而msg是最後乙個確定的引數。
最後乙個確定的引數的含義是指它以後的引數都是可變引數,如果有下面的函式宣告
void demo(char *msg1,char *msg2,...)
那麼這裡的最後乙個確定引數就是msg2。
va_arg(argp,char *)返回當前引數的值,型別為char *,然後將argp指向下乙個變長參
數。從這一步可以看出來我們可以通過va_start和va_arg遍歷所有的變長引數。
va_end 將argp的值置為0。
下面我們看看上述幾個巨集在visual c++.net 2003 中的實現方法。首先是va_list的實現
#ifdef _m_alpha
typedef struct va_list;
#else
typedef char * va_list;
#endif
可以看到va_list實際上是乙個機器型別相關的巨集,除了alpha機器以外,其他機器類
型都被定義為乙個char型別的指標變數,之所以定義為char *是因為可以用該變數逐
位址也就是逐字節對引數進行遍歷。
相關定義。
#elif defined(_m_ix86)
#define _intsizeof(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)_addressof(v) + _intsizeof(v) )
#define va_arg(ap,t) ( *(t *)((ap += _intsizeof(t)) - _intsizeof(t)) )
#define va_end(ap) ( ap = (va_list)0 )
#ifdef __cplusplus
#define _addressof(v) ( &reinterpret_cast(v) )
#else
#define _addressof(v) ( &(v) )
#endif
首先看_intsizeof(n)
我們知道對於ix86,sizeof(int)一定是4的整數倍,所以~(sizeof(int) - 1) )的值一定是
右面[sizeof(n)-1]/2位為0,整個這個巨集也就是保證了右面[sizeof(n)-1]/2位為0,其餘位置
為1,所以_intsizeof(n)的值只有可能是2,4,8,16,......等等,實際上是實現了位元組對齊。
#define va_start(ap,v) ( ap = (va_list)_addressof(v) + _intsizeof(v) )
所以va_start(ap,v)的作用就很明了了,_addressof(v)定義了v的起始位址,_intsizeof(v)定義了v所
占用的記憶體,所以ap 就指向v後面的引數的起始位址。
#define va_arg(ap,t) ( *(t *)((ap += _intsizeof(t)) - _intsizeof(t)) )
ap += _intsizeof(t) 使ap指向了後面乙個引數的位址
而( *(t *)((ap += _intsizeof(t)) - _intsizeof(t)) )相當於返回了目前t型別的引數的值。
#define va_end(ap) ( ap = (va_list)0 )
將變數ap 的值置為0。
通過上述分析,再次印證了我麼前面對可變引數實現的解釋。
因此我們可以總結出變長引數函式的一般實現方法:
1:宣告原型,形如void demo(char *msg,...),注意變長引數的原型宣告中至少要含有
乙個確定引數。
2:用va_list定義儲存函式引數的資料結構,可以理解為乙個指標變數(稍後會解釋)。
4:用va_arg遍歷所有的可變引數。
va list可變引數傳遞
va list va start 是何意?一 寫乙個簡單的可變引數的c函式 下面我們來 如何寫乙個簡單的可變引數的c函式.寫可變引數的 c函式要在程式中用到以下這些巨集 void va start va list arg ptr,prev param type va arg va list arg ...
va list可變引數的函式
include include include include include char vstrcat const char first,len strlen first va start argp,first while p va arg argp,char t 0 va end argp re...
C 遍歷可變引數 va list
前言 在c 中使用可變引數可沒c 中那麼方便,使用起來也很麻煩,想盡辦法搜了很多資料仍然無果,但是確有一些心得。文章 1.2.va list va start va arg va end的原理與使用 正文 一.遍歷可變引數 1.1 傳入的時候指定引數個數 void arg cnt intcnt,va...