c語言中函式的可變引數
1. 要在函式中使用引數,首先要包含, #inlcude
2. stdarg.h 這個標頭檔案中包含了下面的巨集定義:
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
下面將會詳細介紹這些巨集定義
stdarg.h 這個標頭檔案宣告了乙個va_list型別,定義了三個巨集,用來遍歷可變引數列表。
擁有可變引數列表的函式定義中,必須要有乙個va_list型別的變數,這個變數在va_start, va_arg, va_end中將會用到。
va_start(va_list ap, last)
va_start必須第乙個呼叫,它初始化 va_list 型別的變數 ap,引數 last 是可變引數列表的前乙個引數的名字,也就是最後型別已確定的函式引數名;因為這個引數的的位址可能會被巨集va_start用到,所以最好不要是暫存器變數,函式,或者陣列。
type va_arg(va_list ap, type)
巨集va_arg展開後是關於下乙個引數的型別和值的表示式,引數 ap 就是被va_start初始化了的那個va_list型別的引數,引數 type 是明確的型別名。
在va_start呼叫之後的第一次va_arg呼叫返回的是可變引數列表中的第乙個引數,再一次呼叫va_arg返回的是可變列表中下乙個引數(如果還有)。
如果沒有下乙個引數,或者引數型別不匹配,會產生隨機錯誤。
如果ap被傳遞到了函式va_arg中, 當函式返回以後,ap的值就沒有定義了。
void va_end(va_list ap)
每次呼叫va_start就必須相應的呼叫va_end, 呼叫va_end(ap)以後, ap就沒有定義了。
void va_copy(va_list dest, va_list src)
複製va_list型別的變數。
每次呼叫va_copy,必須有相應的va_end呼叫
3. 舉例:
#include
#include
void foo(char *fmt, ...);
int main()
void foo(char *fmt, ...)
va_end(ap);
} 它在函式的定義時,用三個點號'.'表示,用逗號與其它引數分隔.
可變引數的特點:不像固定引數那樣一一對應,也不像固定引數有固定的引數型別和引數名稱;可變引數中個數不
定可是傳入的是乙個引數也可以是多個;可變引數中的每個引數的型別可以不同,也可以相同;可變引數的每個引數並沒有
實際的名稱與之相對應.
由此可見,可變引數的形式非常自由而富有彈生.因些,它給那些天才程式設計師有更大地想象和發揮空間.
然而,更多地自由,同樣也加大操作上的難度.
以下就對可變引數的幾個方面作一定的介紹.
1)可變引數的儲存形式.
大家都知道,一般函式的形參屬於區域性變數.而區域性變數就是儲存在記憶體的棧區(所謂的棧區:由編譯器自動分配釋放,
存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。).可變引數也是儲存在記憶體棧區.
在對函式的形參儲存的時侯,編譯器是從函式的形參的右邊到左邊逐一地壓棧,
這樣保證了棧頂是函式的形參的第乙個引數(從左到右數).而80x86平台下的記憶體分配順序是從高位址記憶體到低位址記憶體.
因此,函式的形參在記憶體的儲存形式如下圖(以fun(int var1,int var2,...,int var3,int var4)為例):
棧區:|棧頂 低位址
|第乙個固定引數var1
|可變引數前的第乙個固定引數var2
|可變引數的第乙個引數
|...
|可變引數的最後乙個引數
|函式的倒數第二個固定引數var3
|函式的最後乙個固定引數var4
|...
|函式的返回位址
|...
|棧底 高位址
2)使用可變引數所用到頭檔案和相關巨集說明
在此,以tc2.0編譯器為參考物件來說明.
可變引數的相關定義在tc2.0的名為"stdarg.h"的標頭檔案中.
此檔案為:
/* stdarg.h
definitions for accessing parameters in functions that accept
a variable number of arguments.
#if !defined(__stdarg)
#define __stdarg
typedef void *va_list;
#define va_start(ap, parmn) (ap = ...)
#define va_arg(ap, type) (*((type *)(ap))++)
#define va_end(ap)
#define _va_ptr (...)
#endif
以上為"stdarg.h"的內容.
該檔案定義了使用可變引數所用到的資料型別:typedef void *va_list;
va_start(ap,parmn)起到初始化,使用得ap指向可變引數的第乙個引數.ap的型別為va_list,
parmn為可變引數的前面乙個固定引數.
va_arg(ap,type)獲得當前ap所指向的引數,並使ap指向可變引數的下乙個引數,type為需要獲得的引數的型別.
va_end(ap) 結束可變引數獲取.
3)可變引數的使用例項
例項目的:用可變引數來實現個數不定的字串的傳遞,並顯示傳遞過來的字串.
#include
#include
#include
void tvararg(int num,...);/*num為可變引數的個數*/
int main(void)
void tvararg(int num,...)
4)可變引數的使用需要注意的問題
1.每個函式的可變引數至多有乙個.
2.va_start(ap,parmn)中parmn為可變引數前的乙個固定引數.
3.可變引數的個數不確定,完全由程式約定.
4.可變引數的型別不確定,完全由va_arg(ap,type)中的type指定,然後就把引數的型別強制轉換.
而printf()中不是實現了識別引數嗎?那是因為函式
printf()是從固定引數format字串來分析出引數的型別,再呼叫va_arg
的來獲取可變引數的.也就是說,你想實現智慧型識別可變引數的話是要通
過在自己的程式裡作判斷來實現的.
5.編譯器對可變引數的函式的原型檢查不夠嚴格,對程式設計人員要求很高.
C語言可變引數列表
c語言中類似於printf這種型別的函式,在呼叫它們時我們傳入的引數的型別和數量都不是固定的,這就需要可變引數列表,要使用可變引數列表,要用到以下幾種巨集。include void va start va list ap,last type va arg va list ap,type void v...
(C語言)可變引數列表
c函式要在程式中用到以下這些巨集 void va start va list arg ptr,prev param type va arg va list arg ptr,type void va end va list arg ptr va list 用來儲存巨集va start va arg和v...
C可變引數列表函式
c語言中可以定義接收不同的引數的函式 可變引數的函式可以接收不同數目的引數,但是需要注意的是c語言中函式的引數個數不能超過5個。可變引數的函式的原型如下int narg sum int arg num,在引數列表中至少要有乙個命名的引數。可變引數函式的實現需要用到va start va arg va...