C 中變參函數的處理方式

C 函數中變化的參數用‘...’ 表示。變化的參數依舊按照C函數傳參的規則入棧,即從右往左依次入棧,保證參數從左往右地址依次升高。數組

解析變參的主要思想是:將變參緩衝區像容納了不一樣類型的數組(固然實際的數組裏的變量類型不多是不一樣的)同樣對待。獲取變參緩衝區首地址,按已知類型進行強轉取值,跳過該值,取出下一個值,取完爲止。函數

 

可是這裏有涉及幾個問題:blog

1,如何知道變參緩衝區的首地址?ast

2,強轉時如何知道該參數的類型?class

3,取出該值後,相應的遊標應該偏移多少才能指向下一個參數首地址?變量

4,什麼時候結束解析過程,即如何知道變參的個數?im

下面依次解答上面的問題:數據

首先先看一段代碼(摘自微軟vadefs.h):img

#elif   defined(_M_IX86)

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#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 )
...
typedef char *  va_list;
#ifdef  __cplusplus
#define _ADDRESSOF(v)   ( &reinterpret_cast<const char &>(v) )
#else
#define _ADDRESSOF(v)   ( &(v) )
#endif
...

#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end

首先應該明確棧中數據成員均按int型字節對齊。棧中的尋址均按int型字節進行。有了這個約定咱們就能解決上面4個問題中最關鍵的兩個問題1,3。di

 

代碼中 _INTSIZEOF(n) 計算出n所佔字節是int字節數的倍數(向上取整)。

_crt_va_start(a,v) 給出變參緩衝區的首地址,等於與第一個變參左側第一個形參的地址加上該形參字節對齊後應占的字節數。

 _crt_va_arg(ap,t) 從宏能夠看出t應該是一種類型。將ap所指地址強轉成t * 而後取出該值,並將ap偏移到下一個參數首地址處。

相信看到這裏,已經知道該怎麼變參了。

至於如何知道參數個數,和參數類型,目前只能傳參來解決,好比printf和scanf經過%來判斷個數,經過%s,%d,%f等中s,d,f來區分類型。

相關文章
相關標籤/搜索