//
////
///作為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...