1.帶可變參數的函數由來
當函數中的參數個數不確定時,這時候就需要帶可變參數的函數!
如我們經常使用的C庫函數printf()實際就是一個可變參數的函數,
其原型為:
int printf( const char* format, ...);
它除了有一個參數format固定以外,后面跟的參數的個數和類型是可變的。例如我們可以有以下不同的調用方法:
printf( "%d ",i); printf( "%s ",s); printf( "the number is %d ,string is:%s ", i, s);
2.帶可變參數函數的實現,
原理:
- 使用了指針參數來解決參數的可變問題,指針參數隨着其移動指向不同的參數;
- C語言的函數形參是從右向左壓入堆棧的,以保證棧頂是第一個參數。
C語言標准庫中頭文件stdarg.h索引的接口包含了一組能夠遍歷變長參數列表的宏。
頭文件
#include <stdarg.h>
幾個宏
(1). va_list 定義一個指針
用來定義一個表示參數表中各個參數的變量,即定義了一個指向參數的指針, 用於指示可選的參數.
如:va_list ap;
(2). va_start(ap,v) 初始化指針
使參數列表指針ap指向函數參數列表中的第一個可選參數,v是位於第一個可選參數之前的固定參數, 或者說最后一個固定參數.通常用於指定可變參數列表中參數的個數!
如有一va函數的聲明是void va_test(char a, char b, char c, ...), 則它的固定參數依次是a,b,c, 最后一個固定參數v為c, 因此就是va_start(ap, c).
(3). va_arg(ap, type) 返回參數列表中指針ap所指的參數, 返回類型為type. 並使指針ap指向參數列表中下一個參數.返回的是可選參數, 不包括固定參數.
(4). va_end(ap) 清空參數列表, 並置參數指針arg_ptr無效.
例:
#include <iostream> #include <stdarg.h> using namespace std; void simple_va_fun(int i,...); int main(int argc,char *argv[]) { simple_va_fun(100); simple_va_fun(100,200); simple_va_fun(100,200,'a'); return 0; } void simple_va_fun(int i,...) { va_list arg_ptr; //定義可變參數指針 va_start(arg_ptr,i); // i為最后一個固定參數 int j=va_arg(arg_ptr,int); //返回第一個可變參數,類型為int char c=va_arg(arg_ptr,char); //返回第二個可變參數,類型為char va_end(arg_ptr); // 清空參數指針 printf( "%d %d %c\n",i,j,c); return; }
/*
輸出為
100 4193388 ?
100 200 ?
100 200 a
*/
思路:
(1)首先在函數里定義一個va_list型的變量,這里是arg_ptr,這個變量是指向參數的指針.
(2)然后用va_start宏初始化變量arg_ptr,這個宏的第二個參數是第一個可變參數的前一個參數,是一個固定的參數.
(3)然后用va_arg返回第一個可變的參數,並賦值給整數j。va_arg的第二個參數是你要返回的參數的類型,這里是int型. 返回第一個可變參數后arg_ptr指向第二個可變參數,用同樣的方法返回並賦值給c,類型為char類型。
(4)最后用va_end宏結束可變參數的獲取。
小結:
可變參數的函數原理其實很簡單,而va系列是以宏定義來定義的,實現跟堆棧相關.我們寫一個可變函數的C函數時,有利也有弊,所以在不必要的場合,我們無需用到可變參數.如果在C++里,我們應該利用C++的多態性來實現可變參數的功能,盡量避免用C語言的方式來實現。
參考
http://www.jb51.net/article/41868.htm