-
可變參數函數
鎖定
在計算機程序設計,一個可變參數函數是指一個函數擁有不定引數,即是它接受一個可變數目的參數。簡單來説,就是函數的參數個數可變,參數類型不定的函數。
不同的編程語言對可變參數函數的支持有很大差異。
- 中文名
- 可變參數函數
- 外文名
- Variable parameter function
- 定 義
- 一個擁有不定引數的函數
- 學 科
- 計算機科學
目錄
可變參數函數簡介
在計算機編程時,可變參數函數中參數是一個可變數目,即這個函數擁有不定引數。
另一種許多語言都實現為可變參數函數的是格式輸出函數,在C語言的printf函數和Common Lisp的format函數就是例子。這些函數都需要一個參數,指定格式的輸出,再讀取可變參數的值進行格式化
[1]
。
另外,可變參數函數在某些語言存在安全問題。例如C語言在沒有長度檢查和類型檢查,在傳入過少的參數或不符的類型時可能會出現溢位的情況,更可能會被利用為攻擊目標。所以,在設計函數時可以先考慮其他替補方案,例如以類型安全的方式——重載。
可變參數函數C/C++中的舉例
要創建一個可變參數函數,必須把省略號(...)放到參數列表後面。函數內部必須定義一個va_list變數。然後使用宏va_start、va_arg和va_end來讀取。例如:
#include <stdio.h> #include <stdarg.h> double average(int count, ...); /* 函數聲明,計算參數的平均值。直到參數為0時停止計算 */ int main(void) /* 測試代碼 */ { double avg; avg = average(3, 2, 1, 5, 0); printf("%f\n", avg); return 0; } double average(int count, ...) { va_list ap; int i, cnt = 0; /* cnt 表示參數個數 */ double tot = 0; /* 參數的和 */ va_start(ap, count); for (i = count; i; i = va_arg(ap, int), cnt++) /* i為當前獲取參數的值 */ tot += i; va_end(ap); /* 將參數列表清空 */ return tot / cnt; }
這個是一段計算平均數的程式碼,可以輸入任意數量的小數並計算平均數,注意計算以0停止計算。請注意,函數不知道參數的數量或它們的類型,這裏要求的類型是double,而且第一個參數傳遞可變參數的數量。在另外的情況下,例如printf,參數的數量和類型都設定在格式字符串中。在這兩種情況下,程序員實際上需要提供正確的參數,如果參數傳遞少了或參數的類型不正確,導致讀入內存的無效區(溢位),這樣會有安全漏洞如格式字符串攻擊。
C++中可變參數的函數是從C中繼承而來,可變參數的函數是指函數的參數個數可變,參數類型不定的函數。我們最常見的就是printf()。
可變參數函數可變參數函數實現原理
指定參數的函數實現很簡單,通過通過指定的參數名訪問就行了。但是如果不指定的呢?函數的調用的參數會進行壓棧處理。而對參數的壓棧是從右到左進行壓棧。而參數和參數之間存放是連續的,也就是説,只要知道第一個參數的地址和類型,以及其他參數的類型,就可以獲取各個參數的地址。
比如:
int printf(const char* format,...) printf("%d and %c,a,b");
這裏的a是int型,b是char型。printf()有3個參數,一個const char*,一個是int,一個是char。所以參數壓棧的順序就是先將b入棧,再將a入棧,最後是format入棧,由於棧是向下(低地址)生長的,所以在知道了format的地址之後,所有的參數地址都可以計算出來。
可變參數函數聲明和定義
可變參數函數的聲明很簡單,對於不定參數部分用“...”表示即可。但是實現原理可以看到,第一個的參數的地址是必須提供的,也就是可變參數必須至少包含一個參數,這個參數用來尋址,實現對所有參數的訪問。
當然通常也會在對第一個參數進行一些特殊處理以方便函數的實現,比如強制指定為參數個數,或者像printf一樣使用格式佔位符來。
可變參數函數C++11/C++14中的舉例
C++11新增了initializer_list物件,當編譯器遇到大括號陣列變成函數的參數時,會自動將大括號陣列轉型成initializer_list物件,因此可以使用此原理來做出“相同型別”參數的可變參數函數。
#include <iostream> using namespace std; template<typename T> T sum(initializer_list<T> il) { T data(0); for (T i : il) data += i; return data; } int main() { cout << sum( { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) << endl; return 0; }
可變參數函數JavaScript中的舉例
function test(){ // 不管函數是否聲明參數,所有的參數都會添加到arguments中,arguments以數組的形式將參數保存起來 var params = arguments; // 以數組的形式輸出 console.log(params); }; test("a");// 結果:["a"] test("a", 1);// 結果:["a", 1] test("a", 1, function(){});// 結果:["a", 1, function (){}]
- 詞條統計
-
- 瀏覽次數:次
- 編輯次數:4次歷史版本
- 最近更新: G敏吖吖