c語言程式設計中有時會遇到一些引數個數可變的函式,例如printf()函式,其函式原型為:
int printf( const char* format, ...);
它除了有乙個引數format固定以外,後面跟的引數的個數和型別是可變的(用三個點「…」做引數佔位符),實際呼叫時可以有以下的形式:
printf("%d",i);
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);
乙個簡單的可變引數的c函式。該函式至少有乙個整數引數,其後佔位符…,表示後面引數的個數不定。在這個例子裡,所有的輸入引數必須都是整數,函式的功能只是列印所有引數的值。函式**如下:
#include
#include
void ******_va_fun(int start, ...)
while(nargvalue != -1);
} 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。注意被調的函式在呼叫時是不知道可變引數的正確數目的,程式設計師必須自己在**中指明結束條件。
附:vprintf的用法
在實際專案中,很多時候都會對printf進行一層封裝,來實現不同級別的列印。對於這種需求,一般有兩種方式可以實現。
一.使用巨集#define來實現。
如:
#define dbg_error 1
#define dbg_warn 2
#define log_printf(level, format, ...) \
do while (0)
或
#define dbg_error 1
#define dbg_warn 2
#define log_printf(level, format, arg...) \
do while (0)
二.借助vprintf實現
原型:int
vprintf(const
char *format, va_list arg);
標頭檔案:
例子:
#include
#include
#define dbg_error 1
#define dbg_warn 2
void log_printf(int level, const char *format, ...)
else
if (level & dbg_warn)
va_end(args);
}
參考文章: C語言中可變引數函式的實現
c語言的可變引數函式的實現需要使用標頭檔案stdarg.h,在該標頭檔案中定義了乙個變數型別va list和三個巨集va start va arg va end 下面將在 中講解這幾個巨集的使用方法。第一種方法是在函式內部手動指定可變引數的型別。首先需要知道可變引數的個數,並作為第乙個引數傳入。由於...
C語言中可變引數函式實現原理
c函式呼叫的棧結構 可變引數函式的實現與函式呼叫的棧結構密切相關,正常情況下c的函式引數入棧規則為 stdcall,它是從右到左的,即函式中的最右邊的引數最先入棧。例如,對於函式 void fun int a,int b,int c 其棧結構為 0x1ffc d 0x2000 a 0x2004 b ...
C語言中可變引數函式實現原理
說的非常詳細,但是有部分口誤,希望只吸取精華 c函式呼叫的棧結構 可變引數函式的實現與函式呼叫的棧結構密切相關,正常情況下c的函式引數入棧規則為 stdcall,它是從右到左的,即函式中的最右邊的引數最先入棧。例如,對於函式 void fun int a,int b,int c 其棧結構為 0x1f...