C語言 可變引數函式

2021-10-02 18:08:06 字數 3070 閱讀 4091

可變引數函式,即引數個數可變的函式。

/* 

* [返回值] [函式名](固定引數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 char

short、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 ...