可變長函式引數

2022-09-01 14:15:23 字數 2841 閱讀 9879

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 置空)。

type va_arg ( va_list ap, type );

功能:返回下乙個引數的值。

va_list :儲存引數的型別資訊。

好了,綜合上面3個巨集和乙個型別可以猜出如何實現c語言可變長引數函式:用 va_start 獲取引數列表(的位址)儲存到 ap 中,用 va_arg 逐個獲取值,最後用 va_end 將 ap 置空。

1.3 舉例

#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」12

3456

78910

11// stdarg.h

#define va_start _crt_va_start

#define va_arg _crt_va_arg

#define va_end _crt_va_end

// vadefs.h

typedefchar*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 之外,其他都很好理解,舉個例子吧

#include 

#include

int main ()

輸出結果:12

34_intsizeof(i) = 4

_intsizeof(f) = 4

_intsizeof("hello,world") = 12

sizeof("hello,world") = 12

既然 sizeof 和 _intsizeof 值一樣,為什麼不直接用 sizeof 呢?幹嘛要寫的那麼複雜?答案是為了位元組對齊(無論32位還是64位機器,sizeof(int)永遠代表機器的位數,明白了吧!^_^)

現在再去看變長引數的實現:其實就是把引數在棧中的位址記錄到 ap 中(通過乙個確定引數 paramn 確定位址),然後逐個讀取值。

此時是否有一種豁然開朗的感覺?至少明白了許多,也清楚了很多。

可能大家也猜到了,我擴充套件要擴充套件什麼了?!^_^

簡單介紹兩種函式呼叫約定

__stdcall (c++預設)

引數從右向左壓入堆疊

函式被呼叫者修改堆疊

函式名(在編譯器這個層次)自動加前導的下劃線,後面緊跟乙個@符號,其後緊跟著引數的尺寸

__cdecl (c語言預設)

引數從右向左壓入堆疊

引數由呼叫者清楚,手動清棧,被呼叫函式不會要求呼叫者傳遞多少引數,呼叫者傳遞過多或者過少的引數,甚至完全不同的引數都不會產生編譯階段的錯誤。

那麼,變參函式的呼叫方式為(也只能是):__cdecl 。

本來打算多寫一點擴充套件的,又擔心會文不符題,所以感興趣的朋友可以去看參考資料中的文章,有一些介紹的很詳細。

可變長引數

由於在c語言中沒有函式過載,解決不定數目函式引數問題變得比較麻煩,即使採用c 如果引數個數不能確定,也很難採用函式過載。對這種情況,提出了指標引數來解決問題。如printf 函式,其原型為 int printf const char format,它除了有乙個引數format固定以外,後面跟的引數的...

可變長引數

可變長引數 指的是在呼叫函式時,傳入的引數個數可以不固定 呼叫函式時,傳值的方式無非兩種,一種是位置實參,另一種是關鍵字實參,因此形參也必須得有兩種解決方法,以此來分別接收溢位的位置實參 與關鍵字實參 形參中的會將溢位的位置實參全部接收,然後儲存元組的形式,然後把元組賦值給後的引數。需要注意的是 後...

可變長引數

可變長引數 public class demo06 double.numbers 為可變長引數,如果有多個引數,那麼可變長引數只能放在最後,否則會出錯 在指定引數型別後加乙個省略號 則此引數為可變引數 乙個方法中只能指定乙個可變引數,它必須是方法的最後乙個引數,任何普通的引數必須在它之前宣告 pub...