當(dāng)我們無法列出傳遞函數(shù)的所有實(shí)參的類型和數(shù)目時(shí),可以用省略號指定參數(shù)表
- (void)parameterList:(NSString *)a,...;
函數(shù)參數(shù)是以數(shù)據(jù)結(jié)構(gòu):棧的形式存取,從右至左入棧。
void func(int x, float y, char z);
調(diào)用函數(shù)的時(shí)候机杜,實(shí)參 char z 先進(jìn)棧帜讲,然后是 float y,最后是 int x椒拗,因此在內(nèi)存中變量的存放次序是 x->y->z似将,因此,從理論上說陡叠,我們只要探測到任意一個(gè)變量的地址玩郊,并且知道其他變量的類型肢执,通過指針移位運(yùn)算枉阵,則總可以找到其他的輸入變量。
獲取參數(shù):
//va_list 是一個(gè)字符指針
//可以理解為指向當(dāng)前參數(shù)的一個(gè)指針
//取參必須通過這個(gè)指針進(jìn)行预茄。
typedef char * va_list;
void va_start ( va_list ap, prev_param );
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
- 在調(diào)用參數(shù)表之前兴溜,定義一個(gè) va_list 類型的變量,(假設(shè)va_list 類型變量被定義為ap)耻陕;
- 然后應(yīng)該對ap 進(jìn)行初始化拙徽,讓它指向可變參數(shù)表里面的第一個(gè)參數(shù),這是通過 va_start 來實(shí)現(xiàn)的诗宣,第一個(gè)參數(shù)是 ap 本身膘怕,第二個(gè)參數(shù)是在變參表前面緊挨著的一個(gè)變量,即“...”之前的那個(gè)參數(shù);
- 然后是獲取參數(shù)召庞,調(diào)用va_arg岛心,它的第一個(gè)參數(shù)是ap,第二個(gè)參數(shù)是要獲取的參數(shù)的指定類型篮灼,然后返回這個(gè)指定類型的值忘古,并且把 ap 的位置指向變參表的下一個(gè)變量位置;
- 獲取所有的參數(shù)之后诅诱,我們有必要將這個(gè) ap 指針關(guān)掉江解,以免發(fā)生危險(xiǎn)匹摇,方法是調(diào)用 va_end,他是輸入的參數(shù) ap 置為 NULL。通常va_start和va_end是成對出現(xiàn)魏烫。
例子:
- (void)parameterList:(int)a,... {
va_list argp; //定義保存函數(shù)參數(shù)的結(jié)構(gòu)
int argno = 0;
int para; //argp指向傳入的第一個(gè)可選參數(shù),a是最后一個(gè)確定的參數(shù)
va_start( argp, a);
while (1) {
para = va_arg( argp, int);
if ( para == 0 ) { break; }
NSLog(@"Parameter #%d is: %d\n", argno, para);
argno++;
}
va_end( argp ); //將argp置為NULL
}
- (void)parameterStringList:(NSString *)msg,...{
va_list argp;
NSString * parameter;
va_start(argp, msg);
while (1) {
parameter = va_arg(argp, NSString *);
if (parameter == nil) { break; }
NSLog(@"parameter: %@", parameter);
}
va_end(argp);
}
運(yùn)行結(jié)果:
可變參數(shù)函數(shù)調(diào)用
References:
http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html