1.1 什麼是可變長引數
可變長引數:顧名思義,就是函式的引數長度(數量)是可變的。比如 c 語言的 printf 系列的(格式化輸入輸出等)函式,都是引數可變的。下面是 printf 函式的宣告:
int printf ( const char * format, ... );
可變引數函式宣告方式都是類似的。
1.2 如何實現
c語言可變引數通過三個巨集(va_start、va_end、va_arg)和乙個型別(va_list)實現的,
void va_start ( va_list ap, paramn );
引數:ap: 可變引數列表位址
paramn: 確定的引數
功能:初始化可變引數列表(把函式在 paramn 之後的引數位址放到 ap 中)。
void va_end ( va_list ap );
功能:關閉初始化列表(將 ap 置空)。
va_list :儲存引數的型別資訊。
好了,綜合上面3個巨集和乙個型別可以猜出如何實現c語言可變長引數函式:用 va_start 獲取引數列表(的位址)儲存到 ap 中,用 va_arg 逐個獲取值,最後用 va_arg 將 ap 置空。
1.3 舉例
/** 功能:用c語言實現變長引數小例:求和
* ide: microsoft visual studio 2010 */
#include
#include
#define end -1
int va_sum (int
first_num, ...)
//關閉引數列表
va_end(ap);
return
result;
}int
main ()
1.4 使用注意事項
巨集定義在 stdarg.h 中,所以使用時,不要忘了新增標頭檔案。
設定乙個引數結束標誌(cplusplus 上說,va_arg 並不能確定哪個引數是最後乙個引數)。
型別的匹配
期待您的補充……
「原始碼面前,一覽無遺」!
以下原始碼,來自「..\microsoft visual studio 10.0\vc\include」
// stdarg.h#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
// vadefs.h
typedef char * va_list;
#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 )
#define _addressof(v) ( &(v) )
#define _intsizeof(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
除了 _intsizeof 之外,其他都很好理解,舉個例子吧:
* 功能:測試 _intsizeof 巨集
* ide: codeblocks 10.05
*/#include #include int main ()
輸出結果:
_intsizeof(i) = 4_intsizeof(f) = 4
_intsizeof("hello,world") = 12
sizeof("hello,world") = 12
既然 sizeof 和 _intsizeof 值一樣,為什麼不直接用 sizeof 呢?幹嘛要寫的那麼複雜?答案是為了位元組對齊(無論32位還是64位機器,sizeof(int)永遠代表機器的位數,明白了吧!^_^)
此時是否有一種豁然開朗的感覺?至少明白了許多,也清楚了很多。
可能大家也猜到了,我擴充套件要擴充套件什麼了?!^_^
簡單介紹兩種函式呼叫約定
__stdcall (c++預設)
引數從右向左壓入堆疊
函式被呼叫者修改堆疊
函式名(在編譯器這個層次)自動加前導的下劃線,後面緊跟乙個@符號,其後緊跟著引數的尺寸
__cdecl (c語言預設)
引數從右向左壓入堆疊
引數由呼叫者清楚,手動清棧,被呼叫函式不會要求呼叫者傳遞多少引數,呼叫者傳遞過多或者過少的引數,甚至完全不同的引數都不會產生編譯階段的錯誤。
那麼,變參函式的呼叫方式為(也只能是):__cdecl 。
C語言可變長引數
在使用可變長引數時發現的乙個問題,首先先放一段 和它的執行結果 產生這樣結果的原因就在於va start的第二個引數不同 原先一直以為va start的第二個引數是引數的個數,查了一些資料,找到va start的定義後發現,va start的第二個引數是可變長引數最左邊的位址。va start的定義...
可變長函式引數
1.1 什麼是可變長引數 可變長引數 顧名思義,就是函式的引數長度 數量 是可變的。比如 c 語言的 printf 系列的 格式化輸入輸出等 函式,都是引數可變的。下面是 printf 函式的宣告 int printf const char format,可變引數函式宣告方式都是類似的。1.2 如何...
C 系列 函式可變長引數
一 基礎部分 1.1 什麼是可變長引數 可變長引數 顧名思義,就是函式的引數長度 數量 是可變的。比如 c 語言的 printf 系列的 格式化輸入輸出等 函式,都是引數可變的。下面是 printf 函式的宣告 int printf const char format,可變引數函式宣告方式都是類似的...