可變引數列表的實現

2022-09-23 16:06:15 字數 1474 閱讀 9861

在學習c語言的過程中,大家是不是和我一樣,認為printf是乙個神一樣的函式?他可以接受不同數目,不同型別的引數,他到底是怎麼實現的呢?

讓我們去看一下它的源**:

printf源**:

int printf(const char *fmt,...)

它採用的是可變引數列表,可變引數列表主要有以下兩個缺點:

1)無法確定可變引數列表的長度,這也是printf提供萬用字元的原因所在;

2)不能提供型別檢查,在實參向形參的拷貝過程中可能會出現問題,一般建議只傳遞基本資料型別

乙個型別:va_list ;三個巨集:va_start ;

首先介紹乙個用可變引數列表實現的乙個函式,在分別介紹他們(一型別,三巨集)

#include

#include

using namespace std;

/*可變引數列表實現求一組不確定數目數值的和*/

int sum(int n,int v1,...)

如上,定義了乙個 va_list型別的變數 arg,可以用該變數作為儲存可變引數列表的指標。實際使用中,如果把可變引數列表的入參看做乙個陣列 array,那麼這個 va_list 就相當於其迭代器 iterator。

這個巨集本身只是個定義,真正賦予其意義的在於下面的幾個巨集。

2)實現:實際上只是乙個 char * 型別的指標,原因這裡不能判定型別,所以用size為1的char型別指標會方便移動。

2、va_start

1)用法:

int sum(int n,int v1,...)

這個巨集需要兩個引數,第乙個是上面定義的 va_list, 第二個是可變引數列表之前的那個引數。

作用就是使得 va_list 的變數指向可變引數列表的首位址。這才是一般意義上的對 va_list的初始化。

2)實現:

#define va_start ( ap, v ) ( ap = (va_list)&v + _intsizeof(v) )

很容易看懂,就是將ap指向v後的位址。

3)注意:

按照規範,va_start中的引數,一定要是最後乙個引數,也就是...之前的那個引數,不然可能會有問題。尤其是windows和linux的函式引數入棧順序不同,會有可移植性問題

3、va_arg

1)用法:

int tmp = va_arg(arg,int);

同樣有兩個引數,第乙個是前面va_list已經初始化好的變數arg ,第二個引數是型別,比如這裡可變引數列表的第乙個引數是int型別,那麼就傳int。

這個函式實現了類似於迭代器的功能,他的返回值是當前itor指向的 int型別值(型別是第二個引數所描述的),同時會移動 itor,使得其指向可變引數列表的下乙個引數。

4、va_end

1)用法:

va_end(arg);

5、缺少的....

作為乙個迭代器,缺少的最關鍵一環就是判定結尾,可惜這裡是沒法提供的。還是老老實實的結尾傳個null吧。

可變引數列表函式實現

如題 我們在寫可變引數列表函式之前,先來了解一下什麼是可變引數列表函式。我們在c語言程式設計中有時會遇到 一些引數個數可變的函式,例如printf 函式,其函式原型為 int printf const char format,它除了有乙個引數format固定以外,後面跟的引數個數和型別是可變的 用三...

可變引數列表

模擬實現printf函式 va list是在c語言中解決變參問題的一組巨集,所在標頭檔案 include 用於獲取不確定個數的引數 va start,函式名稱,讀取可變引數的過程其實就是在堆疊中,使用指標,遍歷堆疊段中的引數列表,從低位址到高位址乙個乙個地把引數內容讀出來的過程 va arg,這個巨...

可變引數列表

小二,上 class a public class varargs two param static void twostringparam string a,string b three param 參照上兩種寫法,一直往後面加。是不是感覺很憂傷 幸好這不是真的。string.a static v...