可變引數函式,即引數個數可變的函式。
/*
* [返回值] [函式名](固定引數m個, 可變引數n個)
* 其中,m>=1, n>=0, 即:
*/// 至少需要乙個固定引數,否則你怎麼定位到引數呢?固定引數的宣告與普通函式引數相同
// 可選引數由於數目不定(0個或以上),宣告時用"…"表示(「…」用作引數佔位符)。固定引數和可選引數共同構成可變引數函式的引數列表。
void
var_params_func1
(int fixed,..
.);void
var_params_func2
(char fixed1,
float fixed2,..
.);
// 舉個最簡單的例子:
#include
void
var_params_func
(int fixed,..
.)intmain
(int argc,
char
**ar**)
----
----
----
----
--輸出結果為:
11,
22,
這時候如果我們希望把可變引數使用起來,怎麼做呢?使用va_list!
va_list是在c語言中解決變參問題的一組巨集,所在標頭檔案:#include ,用於獲取不確定個數的引數。va意為variable-argument(可變引數).
// // 它的定義:
#ifdef _m_alpha
// _m_alpha是指dec alpha(alpha axp)架構。所以一般情況下va_list所定義變數為字元指標。
typedef
struct
va_list;
#else
typedef
char
* va_list;
#endif
// intsizeof 巨集,獲取型別占用的空間長度,最小占用長度為int的整數倍:
#define _intsizeof(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _intsizeof(v) )
#define va_arg(ap,t) ( *(t *)((ap += _intsizeof(t)) - _intsizeof(t)) )
// va_end巨集,清空va_list可變引數列表:
#define va_end(ap) ( ap = (va_list)0 )
/* 使用方法:
* 1.首先在函式裡定義一具va_list型的變數,這個變數用來指向可變引數;
* 2.然後用va_start巨集初始化剛定義的va_list變數;
* 3.然後用va_arg返回可變的引數,va_arg的第二個引數是你要返回的引數的型別(如果函式有多個可變引數的,依次呼叫va_arg獲取各個引數);
* 4.最後用va_end巨集結束可變引數的獲取。
*/#include
#include
void
var_params_func
(int fixed,..
.)intmain
(int argc,
char
**ar**)
----
----
----
----
--輸出結果為:
fixed =
11, var_param1 =
380311080
fixed =
22, var_param1 =
33
由上述結果可見我們把變參使用了起來,這裡需要說明幾點:
我是linux的環境,而且_m_alpha巨集是開啟的,所以我的va_list型別是乙個結構體。
在第一條輸出結果「fixed = 11, var_param1 = 380311080」中,「var_param1 = 380311080」是無效值。當函式沒有變參時,va_arg等系列巨集還是可以正常呼叫的(不會報錯,但是結果是錯的),這裡需要注意下。(形參fixed的堆疊上方內容)
下面引用一篇部落格的總結性語句,寫得很好,有興趣可以開啟看看(
變參巨集根據堆疊生長方向和引數入棧特點,從最靠近第乙個可變引數的固定引數開始,依次獲取每個可變引數的位址。
變參巨集的定義和實現因作業系統、硬體平台及編譯器而異(但原理相似)。system v unix在varargs.h標頭檔案中定義va_start巨集為va_start(va_list arg_ptr),而ansi c則在stdarg.h標頭檔案中定義va_start巨集為va_start(va_list arg_ptr, prev_param)。兩種巨集並不相容,為便於程式移植通常採用ansi c定義。
gcc編譯器使用內建巨集間接實現變參巨集,如#define va_start(v,l) __builtin_va_start(v,l)。因為gcc編譯器需要考慮跨平台處理,而其實現因平台而異。例如x86-64或powerpc處理器下,引數不全都通過堆疊傳遞,變參巨集的實現相比x86處理器更為複雜。
變參巨集無法智慧型識別可變引數的數目和型別,因此實現變參函式時需自行判斷可變引數的數目和型別。前者可顯式提供變引數目或設定遍歷結束條件(如-1、』\0』或回車符等)。後者可顯式提供變參型別列舉值,或在固定引數中包含足夠的型別資訊(如printf函式通過分析format字串即可確定各變參型別),甚至主調函式和被調函式可約定變參的型別組織等。
編譯器對可變引數函式的原型檢查不夠嚴格,不利於程式設計查錯。
va_arg(ap, type)巨集獲取變參時,type不可指定為以下型別:
char、signed char、unsigned charshort、unsigned short
signed short、short int、signed short int、unsigned short int
float
C語言函式可變引數
翻apue的時候,看到了一組可變引數的巨集就是va list 類似 void print arg int count,1 va list變數 ifdef m alpha typedef struct va list else typedef char va list 這個 endif 2 intsi...
C語言可變引數函式
今天在c和指標書中第一次接觸到這個函式,以前有碰到過這樣可變引數的問題,但無從下手。原來c語言還是有這樣的功能,感覺c真是無所不能。c函式要在程式中用到以下這些巨集 void va start va list arg ptr,prev param type va arg va list arg pt...
C語言可變引數函式探秘
c語言的可變引數函式看起來是不很酷,必須printf之類的,初學時,一頭霧水,不禁感覺到宇宙的浩瀚和自己的渺小啊,但是等你知道其中原理之後,也就淡定了 下面首先看乙個程式 include stdarg.h include double addmanynum int n,va end arglist ...