C語言可變引數函式用法

2021-10-08 02:43:42 字數 2886 閱讀 6553

2023年7月14日

參考鏈結

可變引數函式的宣告使用省略號作為最後乙個引數,例如 int printf(const char * format,...); 有關語法和自動引數轉換的更多詳細資訊,請參閱可變引數。

從函式體訪問可變引數使用以下巨集:

以下巨集在中定義

va_start

允許訪問可變引數函式引數(函式巨集)

va_arg

訪問下乙個可變引數函式引數(函式巨集)

va_copy(c99)

製作可變引數函式引數(函式巨集)的副本

va_end

結束可變引數函式引數(函式巨集)的遍歷

va_list(變數)

儲存可變引數的變數

它的實現原理利用了記憶體的壓棧技術,將引數壓入(push)棧內,使用時,再逐個從棧裡pop出來。需要注意的是,壓棧的順序是從最右邊引數開始的,再向左逐個壓入,根據棧的原理,在取引數時,就從第乙個可變引數開始了。

先定義乙個va_list型別的變數,比如ptr,它指向引數列表的首位址;

用va_start巨集初始化ptr,它的第二個引數是第乙個可變引數的前乙個引數,即最後乙個固定引數;

用va_arg返回可變的引數,它的第二個引數是要獲取的變參型別;

可以通過反覆呼叫va_arg來依次取得變參值;

最後用va_end巨集結束可變引數的獲取;

定義的函式必須至少有乙個固定引數;這麼做的目的很明顯,就是要定位變參的首位址,也就是固定引數位址+sizeof(固定引數型別)啦;

固定引數和可變引數之間可以沒有任何關係;雖然經典的printf函式中,第乙個固定引數裡(格式化字串)包含了後續變參的型別,但是這僅僅是函式功能的需要,語法上沒有任何要求。

例1

#include #include void ******_printf(const char* fmt, ...)

else if (*fmt == 'c') else if (*fmt == 'f')

++fmt;

}va_end(args);

}int main(void)

輸出: 3

a1.999000

42.500000

ps:在接收char的時候,會進行預設引數提公升,變成int,所以需要以int型來接收char,同樣,float也需要以double來接收,否則會出現編譯錯誤。

e:\clion\shiyan1\main.c: in function '******_printf':

e:\clion\shiyan1\main.c:36:34: warning: 'char' is promoted to 'int' when passed through '...'

int c = va_arg(args, char);

^e:\clion\shiyan1\main.c:36:34: note: (so you should pass 'int' not 'char' to 'va_arg')

e:\clion\shiyan1\main.c:36:34: note: if this code is reached, the program will abort

那麼c語言中什麼時候會牽扯到預設引數提公升呢?

在c語言中,呼叫乙個不帶原型宣告的函式時:呼叫者會對每個引數執行「預設實際引數提公升(default argument promotions)。

同時,對可變長引數列表超出最後乙個有型別宣告的形式引數之後的每乙個實際引數,也將執行上述提公升工作。

提公升工作如下:

——float型別的實際引數將提公升到double

——char、short和相應的signed、unsigned型別的實際引數提公升到int

——如果int不能儲存原值,則提公升到unsigned int 關於預設引數提公升,具體可以參考 如下鏈結 例2

#if 1

#include #include #include #include void ******_printf_2(const char *fmt,...)else if(*fmt == '\r' || *fmt == '\n')else

switch(*fmt)

case 'd':

case 'c':

case 'f':}}

}va_end(args);

}int main(void)

#endif

輸出 jzywdsqa

3jzy

ajzy

1.999000dcff

42.500000

例3

#include #include #include double sample_stddev(int count, ...) 

va_end(args1);

double mean = sum / count;

/* compute standard deviation with args2 and mean. */

double sum_sq_diff = 0;

for (int i = 0; i < count; ++i)

va_end(args2);

return sqrt(sum_sq_diff / count);}

int main(void)

輸出: 0.920258

最後還需要說明兩點。首先,上面講的內容與c語言的實現有關,而c語言的實現又依賴於cpu和作業系統,所以並不適用於所有的計算機,而且隨機器的不同會由很大的區別。在內會看到大量的條件編譯就是這個原因。其次,雖然函式定義中使用可變引數列表提供了很大的靈活性,但是對可變部分的引數c語言編譯器不會進行型別檢查,所以程式中要特別小心,確保引數的傳遞和接受是正確的。

小白記錄學習過程,若有不對,可以討論!

C語言函式可變引數

翻apue的時候,看到了一組可變引數的巨集就是va list 類似 void print arg int count,1 va list變數 ifdef m alpha typedef struct va list else typedef char va list 這個 endif 2 intsi...

C語言可變引數函式

今天在c和指標書中第一次接觸到這個函式,以前有碰到過這樣可變引數的問題,但無從下手。原來c語言還是有這樣的功能,感覺c真是無所不能。c函式要在程式中用到以下這些巨集 void va start va list arg ptr,prev param type va arg va list arg pt...

C語言 可變引數函式

可變引數函式,即引數個數可變的函式。返回值 函式名 固定引數m個,可變引數n個 其中,m 1,n 0,即 至少需要乙個固定引數,否則你怎麼定位到引數呢?固定引數的宣告與普通函式引數相同 可選引數由於數目不定 0個或以上 宣告時用 表示 用作引數佔位符 固定引數和可選引數共同構成可變引數函式的引數列表...