定義不定參數函數,要用到下面這些宏:
- va_start(ap, farg): 初始化一個va_list變量ap,farg是第一個形參
- va_arg(ap, type): 獲取(下)一個type類型的參數
- va_end(ap): 結束使用ap
C語言里編寫不定參數函數的形式是這樣的:
#include <stdarg.h>
int sum(int cnt,...) {
int sum = 0;
int i;
va_list ap;
va_start(ap, cnt);
for(i = 0; i < cnt; ++i)
sum += va_arg(ap, int);
va_end(ap);
return sum;
}
定義不定參數函數,要用到下面這些宏:
- va_start(ap, farg): 初始化一個va_list變量ap,farg是第一個形參
- va_arg(ap, type): 獲取(下)一個type類型的參數
- va_copy(ap): 用於復制參數列表
- va_end(ap): 結束使用ap
這些宏定義一般在stdarg.h
里。
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
注意: 上面這些宏定義會因不同的系統和不同的處理器架構而不同
_INTSIZEOF宏
_INTSIZEOF這個宏的位運算意義比較難理解,乍一看以為是表示多少個int型的長度,其實它運算出來的結果是按照int型對齊后的長度。比如int型為4個字節,_INTSIZEOF(1)、_INTSIZEOF(2)、_INTSIZEOF(3)、_INTSIZEOF(4)的結果都是4,_INTSIZEOF(5)、_INTSIZEOF(6)、_INTSIZEOF(7)、_INTSIZEOF(8)的結果都是8,這正是x86架構CPU下的參數傳遞方式,32位即4字節對齊。
幾個注意事項
- 不定參數的函數至少要有一個固定的參數,因為要用它來初始化va_list,比如上面代碼中sum函數的cnt參數,同時它也表明了傳遞的參數的個數。
常用方式
不定參數函數最常用來格式化字符串,一個比較常見的場景是我們想輸出一些log消息,但又不能直接在控制台輸出,需要自己寫一個log函數來格式化log消息並輸出。這時我們可以用vsprintf函數:
void log(const char *format, ...) {
char buf[MAX_BUF_SIZE];
va_list ap;
va_start(ap, format);
vsprintf(buf, format, ap);
OUTPUT(buf);
}
vsprintf函數的前兩個參數和sprintf的前兩個參數意義相同,只不過后面的不定參換成了va_list類型的參數列表,這正是讓我們用來定義自己的格式化函數的。