可變長度函式引數的原理及使用

2021-05-06 13:18:16 字數 2728 閱讀 2433

概述

由於在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,...