假設我有一個帶有可變數量參數的C函數:如何調用另外一個函數,該函數須要從其內部獲取可變數量的參數,並將全部參數傳遞到第一個函數中? less
例: 函數
void format_string(char *fmt, ...); void debug_print(int dbg_lvl, char *fmt, ...) { format_string(fmt, /* how do I pass all the arguments from '...'? */); fprintf(stdout, fmt); }
羅斯的解決方案有點清理乾淨了。 僅當全部args都是指針時纔有效。 若是__VA_ARGS__
爲空(Visual Studio C ++和GCC都這樣作),語言實現也必須支持__VA_ARGS__
之前的逗號。 spa
// pass number of arguments version #define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__}; _actualFunction(args+1,sizeof(args) / sizeof(*args) - 1);} // NULL terminated array version #define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__, NULL}; _actualFunction(args+1);}
我不肯定這是否適用於全部編譯器,但它對我來講已經有用了。 debug
void inner_func(int &i) { va_list vars; va_start(vars, i); int j = va_arg(vars); va_end(vars); // Generally useless, but should be included. } void func(int i, ...) { inner_func(i); }
若是須要,能夠將...添加到inner_func(),但不須要它。 它起做用,由於va_start使用給定變量的地址做爲起點。 在這種狀況下,咱們在func()中給它一個變量的引用。 因此它使用該地址並在堆棧以後讀取變量。 inner_func()函數從func()的堆棧地址讀取。 所以,只有兩個函數使用相同的堆棧段時纔有效。 指針
若是你給它們任何var做爲起點,那麼va_start和va_arg宏一般會起做用。 所以,若是您但願您能夠將指針傳遞給其餘函數並使用它們。 您能夠輕鬆製做本身的宏。 全部的宏都是類型轉換內存地址。 然而,使它們適用於全部編譯器和調用約定是使人討厭的。 所以,使用編譯器附帶的內容一般更容易。 code
要傳遞省略號,您必須將它們轉換爲va_list並在第二個函數中使用該va_list。 特別; orm
void format_string(char *fmt,va_list argptr, char *formatted_string); void debug_print(int dbg_lvl, char *fmt, ...) { char formatted_string[MAX_FMT_SIZE]; va_list argptr; va_start(argptr,fmt); format_string(fmt, argptr, formatted_string); va_end(argptr); fprintf(stdout, "%s",formatted_string); }
沒有辦法調用(例如)printf而不知道你傳遞了多少個參數,除非你想進入頑皮和非便攜的技巧。 內存
一般使用的解決方案是始終提供另外一種形式的vararg函數,所以printf
具備vprintf
,它使用va_list
代替...
...
版本只是va_list
版本的包裝器。 編譯器
你也能夠嘗試宏。 string
#define NONE 0x00 #define DBG 0x1F #define INFO 0x0F #define ERR 0x07 #define EMR 0x03 #define CRIT 0x01 #define DEBUG_LEVEL ERR #define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: " #define WHEREARG __FILE__,__func__,__LINE__ #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define DEBUG_PRINT(X, _fmt, ...) if((DEBUG_LEVEL & X) == X) \ DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__) int main() { int x=10; DEBUG_PRINT(DBG, "i am x %d\n", x); return 0; }