概述
由於在c語言中沒有函式過載,解決不定數目函式引數問題變得比較麻煩;即使採用c++,如果引數個數不能確定,也很難採用函式過載.對這種情況,有些人採用指標引數來解決問題。下面就c語言中處理不定引數數目的問題進行討論。
定義大家先看幾巨集.
在vc++6.0的include有乙個stdarg.h標頭檔案,有如下幾個巨集定義:
#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)) ) //下乙個引數位址
#define va_end(ap) ( ap = (va_list)0 ) // 將指標置為無效
如果對以上幾個巨集定義不理解,可以略過,接這看後面的內容。
引數在堆疊中分布,位置
在 程序中,堆疊位址是從高到低分配的.當執行乙個函式的時候,將引數列表入棧,壓入堆疊的高位址部分,然後入棧函式的返回位址,接著入棧函式的執行**,這 個入棧過程,堆疊位址不斷遞減,一些黑客就是在堆疊中修改函式返回位址,執行自己的**來達到執行自己插入的**段的目的.總之,函式在堆疊中的分布情況是:位址從高到低,依次是:函式引數列表,函式返回位址,函式執行**段。堆疊中,各個函式的分布情況是倒序的。即最後乙個引數在列表中位址最高部分,第乙個引數在列表位址的最低部分.引數在堆疊中的分布情況如下:
最後乙個引數
倒數第二個引數
...
第乙個引數
函式返回位址
函式**段
示例**
void arg_test(int i, ...);
int main(int argc,char *argv)
void arg_test(int i, ...)
**說明:
int int_size = _intsizeof(int);得到int型別所佔位元組數
va_start(arg_ptr, i); 得到第乙個可變引數位址, 根據定義(va_list)&v得到起始引數的位址, 再加上_intsizeof(v) ,就是其實引數下乙個引數的位址,即第乙個可變引數位址.
j=va_arg(arg_ptr, int); 得到第乙個參引數的值,並且arg_ptr指標上移乙個_intsizeof(int),即指向下乙個可變引數的位址.
va_end(arg_ptr);置空arg_ptr,即arg_ptr=0;
總結:讀取可變引數的過程其實就是堆疊中,使用指標,遍歷堆疊段中的引數列表,從低位址到高位址乙個乙個地把引數內容讀出來的過程.
在程式設計中應該注意的問題和解決辦法
雖然可以通過在堆疊中遍歷引數列表來讀出所有的可變引數,但是由於不知道可變引數有多少個,什麼時候應該結束遍歷,如果在堆疊中遍歷太多,那麼很可能讀取一些無效的資料.
解決辦法:a.可以在第乙個起始引數中指定引數個數,那麼就可以在迴圈還中讀取所有的可變引數;b.定義乙個結束標記,在呼叫函式的時候,在最後乙個引數中傳遞這個標記,這樣在遍歷可變引數的時候,可以根據這個標記結束可變引數的遍歷;
下面是一段示例**:
//第乙個引數定義可選引數個數,用於迴圈取初引數內容
void arg_cnt(int cnt, ...);
int main(int argc,char *argv)
void arg_cnt(int cnt, ...)
}雖 然可以根據上面兩個辦法解決讀取引數個數的問題,但是如果引數型別都是不定的,該怎麼辦,如果不知道引數的型別,即使讀到了引數也沒有辦法進行處理.解決 辦法:可以自定義一些可能出現的引數型別,這樣在可變引數列表中,可以可變引數列表中的那型別,然後根據型別,讀取可變引數值,並進行準確地轉換.傳遞參 數的時候可以這樣傳遞:引數數目,可變引數型別1,可變引數值1,可變引數型別2,可變引數值2,....
這裡給出乙個完整的例子:
#include
#include
const int int_type = 100000;
const int str_type = 100001;
const int char_type = 100002;
const int long_type = 100003;
const int float_type = 100004;
const int double_type = 100005;
//第乙個引數定義可選引數個數,用於迴圈取初引數內容
//可變引數採用arg_type,arg_value...的形式傳遞,以處理不同的可變引數型別
void arg_type(int cnt, ...);
//第乙個引數定義可選引數個數,用於迴圈取初引數內容
void arg_cnt(int cnt, ...);
//測試va_start,va_arg的使用方法,函式引數在堆疊中的位址分布情況
void arg_test(int i, ...);
int main(int argc,char *argv)
void arg_test(int i, ...)
void arg_cnt(int cnt, ...)
}void arg_type(int cnt, ...)}}
Python 可變長度引數
def test args first,args print 第乙個引數first是 format first for arg in args print args 的值為 format arg test args 1,2,3,4,5 test args a args 重點是 args可以被任意變數...
可變長函式引數
1.1 什麼是可變長引數 可變長引數 顧名思義,就是函式的引數長度 數量 是可變的。比如 c 語言的 printf 系列的 格式化輸入輸出等 函式,都是引數可變的。下面是 printf 函式的宣告 int printf const char format,可變引數函式宣告方式都是類似的。1.2 如何...
Python 2 3 可變長度引數
可變長度指的是在呼叫函式時,傳入的值 實參 的個數不固定 對於溢位的實參必須有對應的形參來接受 一 可變長度的位置引數 def func a,b,args args 3,4,5,6,7,8 print a,b,args,type args func 1,2,3,4,5,6,7,8 結果 1 2 3,...