原理解釋:
va_list 是在c語言中解決變參問題的一組巨集,在標頭檔案下。
va_list的用法:
(1)首先在函式裡定義一具
va_list型的變數
,這個變數是
指向引數的指標
(2)然後用
va_start巨集初始化變數剛定義的va_list變數
,這個巨集的第二個引數是
第乙個可變引數的前乙個參
數,是乙個固定的引數。
(3)然後用
va_arg返回可變的參
數,va_arg的第二個引數是你要返回的引數的型別。
(4)最後用
va_end巨集結束可變引數的獲取
。然後你就可以在函式裡使用第二個引數了。如果函式有多個可變引數的,依次呼叫va_arg獲取各個引數。
va_list在編譯器中的處理:
(1)在執行
va_start(ap,v)
以後,ap
指向第乙個可變引數在堆疊的位址
。(2)va_arg()取得型別t的可變引數值,在這步操作中首先
apt = sizeof(t型別)
,讓。然後返回ap-sizeof(t型別)的t型別*指標,這正是 第乙個可變引數在堆疊裡的位址。然後用*取得這個位址的內容。
(3)va_end(),x86平台定義為ap = ((char*)0),使ap不再指向堆疊,而是跟null一樣,有些直接定義為((void*)0),這樣編譯器不會為va_end產生**,例如gcc在linux的x86平台就是這樣定義的。
要注意的是:由於
引數的位址用於va_start巨集
,所以引數不能宣告為暫存器變數
,或作為函式或陣列型別。
使用va_list應該注意的問題:
(1)因為va_start, va_arg, va_end等定義成巨集,所以它顯得很愚蠢,可變引數的型別和個數完全在該函式中由程式**控制,它並不能智慧型地識別不同引數的個數和型別. 也就是說,你想實現智慧型識別可變引數的話是要通過在自己的程式裡作判斷來實現的.
(2)另外有乙個問題,因為編譯器對可變引數的函式的原型檢查不夠嚴格,對程式設計查錯不利.不利於我們寫出高質量的**。
小結:可變引數的函式原理其實很簡單,而va系列是以巨集定義來定義的,實現跟堆疊相關。我們寫乙個可變函式的c函式時,有利也有弊,所以在不必要的場合,我們無需用到可變引數,如果在c++裡,我們應該利用c++多型性來實現可變引數的功能,盡量避免用c語言的方式來實現。
va_list ap; //宣告乙個變數來轉換引數列表
va_start(ap,fmt); //初始化變數
va_end(ap); //結束變數列表,和va_start成對使用
可以根據va_arg(ap,type)取出引數
已經經過除錯成功的輸出程式
#include
#include
#define bufsize 80
char buffer[bufsize];
int vspf(char *fmt, ...)
int main(void)
執行結果為:
30 90.000000 abc
va start va end 函式應用
1 當無法列出傳遞函式的所有實參的型別和數目時,可用省略號指定參數列 void foo void foo parm list,2 函式引數的傳遞原理 函式引數是以資料結構 棧的形式訪問,從右至左入棧.eg include void fun int a,int main output 1 2 3 4 ...
va start va end 的使用和原理
1 當無法列出傳遞函式的所有實參的型別和數目時,可用省略號指定參數列 void foo void foo parm list,2 函式引數的傳遞原理 函式引數是以資料結構 棧的形式訪問,從右至左入棧.eg 先介紹一下可變參數列的呼叫形式以及原理 首先是引數的記憶體存放格式 引數存放在記憶體的堆疊段中...
va start va end 的使用和原理
1 當無法列出傳遞函式的所有實參的型別和數目時,可用省略號指定參數列 void foo void foo parm list,2 函式引數的傳遞原理 函式引數是以資料結構 棧的形式訪問,從右至左入棧.eg 先介紹一下可變參數列的呼叫形式以及原理 首先是引數的記憶體存放格式 引數存放在記憶體的堆疊段中...