c 中如何寫引數不定的函式

2021-07-22 16:15:37 字數 3334 閱讀 4113

//

////

///作為va_list,va_start的練習,可以學習一下使用_vsnprintf函式

#include 

#include 

void formatoutput(char*

format, ...)

void

main()

/引數個數不定的函式,最頻繁使用的就是printf()與scanf()。其實,我們也可以自己實現這樣的功能,首先看

乙個例子:

#include

#include

int sum(int first, int second, ...)

va_end(vl);

return sum;}

int main(int argc, char* argv)

在上面的例子中,實現了乙個引數個數不定的求int型和的函式sum()。函式中一開始定義了乙個va_list型變數

vl,該變數用來訪問可變引數,實際上就是指標,接著使用va_start使vl指向第乙個引數,然後再使用va_arg

來遍歷每乙個引數,va_arg返回引數列表中的當前引數並使vl指向引數列表中的下乙個引數。最後通過va_end

把vl指標清為null。在這裡,va_start,va_arg,va_end其實都是巨集,那麼這些巨集又是如何實現他們的功能的

呢?乙個很顯然的問題就是既然引數個數在函式呼叫之前沒有確定,所以,在函式定義的時候沒有辦法像普通函式

那樣使用確定的變數來接受傳進來的引數,於是,問題的關鍵就是如何接收到這些不確定的引數了?首先,看

看函式呼叫時實際發生的情況,在函式呼叫的時候,使用棧傳遞引數,拿上例來說,如果呼叫sum(30, 20, 10,

-1),那麼引數入棧後的情形如下圖所示(假定按照自右至左的順序入棧):

既然引數在棧中的情形已經知道了,那麼,如果使用指標(程式中的vl)指向第乙個引數(va_start(vl,

first)),因為所有引數都是連續存放的,通過移動指標就可以訪問到每乙個引數了(va_arg(vl, int)),這

就是我在程式中使用到那幾個巨集的實現思想。

明白了以上原理之後,就可以完全不使用巨集,自己實現這樣的乙個功能了,下面的程式是我按照上面的

思想改寫的:

#include

int sum(int first, int second, ...)

return sum;}

int main(int argc, char* argv)

可以看出,通過使用指標的確實現了引數個數不定的函式了,但是程式中還有乙個問題,那就是移動指標,在

程式中因為我使用的引數都是相同的int型別,所以可以事先知道訪問下乙個引數的時候應該移動sizeof(int)

個位元組,但是,如果引數的型別不同呢?這的確是個比較麻煩的問題,因為不同的資料型別占用的位元組數可能

是不一樣的(如double型為8個字元,short int型為2個),所以很難事先確定應該移動多少個位元組!但是辦法

還是有的,這就是使用指標了,無論什麼型別的指標,都是占用4個位元組,所以,可以把所有的傳人引數都設定

為指標,這樣一來,就可以通過移動固定的4個位元組來實現遍歷可變引數的目的了,至於如果取得指標中的內容

並使用他們,當然也是無法預先得知的了,所以這大概也就是像printf(),scanf()之類的函式還需要乙個格式

控制符的原因吧^_^!不過實現起來還是有不少麻煩,暫且盜用vprintf()來實現乙個與printf()函式一樣功能的

函式了,**如下:

void myprint(const char *frm, ...)

//

書上說,當無法列出傳遞函式的所有實參的型別和數目時,可用省略號指定參數列(...)

如:void foo(...);

void foo(parm_list,...);

void foo(...)

呼叫:foo(a,b,c);

就是不懂,把a,b,c的值傳進函式裡面後,用什麼變數來接收???如果不能接收,(...)豈不是沒意義?

還有就是不明白

int printf(const char*...);

printf("hello,&s\n",username);

這個c的輸出函式是怎麼用(...)實現的.

先謝了:)

re:

首先函式體中宣告乙個va_list,然後用va_start函式來獲取引數列表中的引數,使用完畢後呼叫va_end()結束。像這段**: 

void testfun(char* pszdest, int destlen, const char* pszformat, ...) 

///乙個簡單的可變引數的c函式

先看例子程式。該函式至少有乙個整數引數,其後佔位符…,表示後面引數的個數不定。在這個例子裡,所有的輸入引數必須都是整數,函式的功能只是列印所有引數的值。函式**如下:

//示例**1:可變引數函式的使用

#include "stdio.h"

#include "stdarg.h"

void ******_va_fun(int start, ...) 

while(nargvalue != -1);                

return; 

}int main(int argc, char* argv)

下面解釋一下這些**。從這個函式的實現可以看到,我們使用可變引數應該有以下步驟:

⑴由於在程式中將用到以下這些巨集: 

void va_start( va_list arg_ptr, prev_param ); 

type va_arg( va_list arg_ptr, type ); 

void va_end( va_list arg_ptr ); 

va在這裡是variable-argument(可變引數)的意思。

這些巨集定義在stdarg.h中,所以用到可變引數的程式應該包含這個標頭檔案。

⑵函式裡首先定義乙個va_list型的變數,這裡是arg_ptr,這個變數是儲存引數位址的指標.因為得到引數的位址之後,再結合引數的型別,才能得到引數的值。

⑶然後用va_start巨集初始化⑵中定義的變數arg_ptr,這個巨集的第二個引數是可變引數列表的前乙個引數,即最後乙個固定引數。

⑷然後依次用va_arg巨集使arg_ptr返回可變引數的位址,得到這個位址之後,結合引數的型別,就可以得到引數的值。

⑸設定結束條件,這裡的條件就是判斷引數值是否為-1。注意被調的函式在呼叫時是不知道可變引數的正確數目的,程式設計師必須自己在**中指明結束條件。至於為什麼它不會知道引數的數目,在看完這幾個巨集的內部實現機制後,自然就會明白。

c 中如何寫引數不定的函式

作為va list,va start的練習,可以學習一下使用 vsnprintf函式 include stdio.h include stdarg.h void formatoutput char format,void main 引數個數不定的函式,最頻繁使用的就是printf 與scanf 其實...

python函式如何寫 python如何寫函式

python函式的定義 定義函式,也就是建立乙個函式,可以理解為建立乙個具有某些用途的工具。定義函式需要用 def 關鍵字實現,具體的語法格式如下 def 函式名 形參列表 由零條到多條可執行語句組成的 塊 return 返回值 其中,用 括起來的為可選擇部分,即可以使用,也可以省略。此格式中,各部...

C 函式中如何接收數量不定的函式引數

下面,我們來看一下,如果在c 的函式中接收數量不定的函式引數。這種形式如同在c 的函式引數列表中使用params 型別的引數。我們可以將函式定義成能夠接受任意數量的實參。通過將省略號 3個句點.寫在函式定義中形參列表的最後,即可表示呼叫該函式時可以提供數量可變的實參。例如 int sumvalues...