可變長引數

2021-07-24 14:08:37 字數 2093 閱讀 6508

由於在c語言中沒有函式過載,解決不定數目函式引數問題變得比較麻煩,即使採用c++,如果引數個數不能確定,也很難採用函式過載。對這種情況,提出了指標引數來解決問題。

如printf()函式,其原型為:

int   printf(   const   char*   format,   ...);

它除了有乙個引數format固定以外,後面跟的引數的個數和型別是可變的,例如我們可以有以下不同的呼叫方法:   

printf( "%d ",i);   

printf( "%s ",s);   

printf( "the   number   is   %d   ,string   is:%s ",   i,   s);   

如何實現其功能?

我們需要以下幾個巨集定義:

(1)va_list 

定義了乙個指標arg_ptr, 用於指示可選的引數.

(2)va_start(arg_ptr, argn)

使引數列表指標arg_ptr指向函式引數列表中的第乙個可選引數,argn是位於第乙個可選引數之前的固定引數, 或者說最後乙個固定引數.如有一va函式的宣告是void va_test(char a, char b, char c, ...), 則它的固定引數依次是a,b,c, 最後乙個固定引數argn為c, 因此就是va_start(arg_ptr, c).

(3)va_arg(arg_ptr, type)

返回引數列表中指標arg_ptr所指的引數, 返回型別為type. 並使指標arg_ptr指向引數列表中下乙個引數.返回的是可選引數, 不包括固定引數.

(4)va_end(arg_ptr)

清空引數列表, 並置引數指標arg_ptr無效.

(注:va在這裡是variable-argument(可變引數)的意思.   這些巨集定義在stdarg.h中,所以用到可變引數的程式應該包含這個標頭檔案)

也需你現在還是不能理解,別著急,現在從乙個例項著手.定義這麼乙個函式,函式的第乙個引數是固定的,其餘引數是可變的。定義為:

void   ******_va_fun(int i,...); 其**為:

1 #include 

2 #include

3using

namespace std;

4void ******_va_fun(int i,...);56

int main(int argc,char *argv)

7 13

14void ******_va_fun(int i,...)

15

**執行解釋:   

(1)首先在函式裡定義乙個va_list型的變數,這裡是arg_ptr,這個變數是指向引數的指標.   

(2)然後用va_start巨集初始化變數arg_ptr,這個巨集的第二個引數是第乙個可變引數的前乙個引數,是最後乙個固定的引數.   

(3)然後用va_arg返回第乙個可變的引數,並賦值給整數j。va_arg的第二個引數是你要返回的引數的型別,這裡是int型.  返回第乙個可變引數後arg_ptr指向第二個可變引數,用同樣的方法返回並賦值給c,型別為char型別。 

(4)最後用va_end巨集結束可變引數的獲取。

小結:

可變引數的函式原理其實很簡單,而va系列是以巨集定義來定義的,實  現跟堆疊相關.我們寫乙個可變函式的c函式時,有利也有弊,所以在不必要的場合,我們無需用到可變引數.如果在c++裡,我們應該利用c++的多型性來實現可變引數的功能,盡量避免用c語言的方式來實現。

附加:

引數在堆疊中分布:

在程序中,堆疊位址是從高到低分配的.當執行乙個函式的時候,將引數列表入棧,壓入堆疊的高位址部分,然後入棧函式的返回位址,接著入棧函式的執行**,這個入棧過程,堆疊位址不斷遞減,一些黑客就是在堆疊中修改函式返回位址,執行自己的**來達到執行自己插入的**段的目的. 總之,函式在堆疊中的分布情況是:位址從高到低,依次是:函式引數列表,函式返回位址,函式執行**段. 堆疊中,各個函式的分布情況是倒序的.即最後乙個引數在列表中位址最高部分,第乙個引數在列表位址的最低部分.引數在堆疊中的分布情況如下: 

最後乙個引數 

倒數第二個引數 

... 

第乙個引數 

函式返回位址 

函式**段

可變長引數

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

可變長引數

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

可變長引數

可變長引數 指的是在呼叫函式時,傳入的引數個數可以不固定 呼叫函式時,傳值的方式無非兩種,一種是位置實參,另一種是關鍵字實參,因此形參也必須得有兩種解決方法,以此來分別接收溢位的位置實參 與關鍵字實參 可變長引數 args會接受多於的位置實參,盡量不使用其他的變數名,而應該使用args,args是約...