Objective-C中可選參數(shù)的實(shí)現(xiàn)

代碼:


-(NSString*)makeDrink:(NSString*)drink Fruit:(NSString*)fruit Food:(NSString*)foodOne,...;

{

NSMutableArray* arr = [[NSMutableArrayalloc]init];

va_listparams;

idargument;

if(foodOne) {

va_start(params, foodOne);

while((argument =va_arg(params,id))) {

[arraddObject:argument];

}

va_end(params);

}

returnnil;

}

------------------------------------------------------------

用法:


Person *man = [Person alloc] init];

[man makeDrink:@"beer" Fruit:@"banana" Food:@"rice",@"beef",@"fish",@"potato",@"vegetables",nil];

------------------------------------------------------------

知識(shí)點(diǎn):


va_list/va_start/va_arg/va_end這幾個(gè)宏,都是用于函數(shù)的可變參數(shù)的。

我們來(lái)看看在vs2008中,它們是怎么定義的:

1:///stdarg.h

2:#defineva_start _crt_va_start

3:#defineva_arg _crt_va_arg

4:#defineva_end _crt_va_end

5:

6:///vadefs.h

7:#define_ADDRESSOF(v)? ( &reinterpret_cast(v) )

8:? typedefchar*? va_list;

9:#define_INTSIZEOF(n)? ( (sizeof(n) +sizeof(int) - 1) & ~(sizeof(int) - 1) )

10:#define_crt_va_start(ap,v)? ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

11:#define_crt_va_arg(ap,t)? ? ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

12:#define_crt_va_end(ap)? ? ? ( ap = (va_list)0 )


代碼原圖


再看看各個(gè)宏的功能是什么?

va_list用于聲明一個(gè)變量,我們知道函數(shù)的可變參數(shù)列表其實(shí)就是一個(gè)字符串,所以va_list才被聲明為字符型指針,這個(gè)類型用于聲明一個(gè)指向參數(shù)列表的字符型指針變量,例如:va_list ap;//ap:arguement pointer

va_start(ap,v),它的第一個(gè)參數(shù)是指向可變參數(shù)字符串的變量,第二個(gè)參數(shù)是可變參數(shù)函數(shù)的第一個(gè)參數(shù),通常用于指定可變參數(shù)列表中參數(shù)的個(gè)數(shù)。

va_arg(ap,t),它的第一個(gè)參數(shù)指向可變參數(shù)字符串的變量,第二個(gè)參數(shù)是可變參數(shù)的類型。

va_end(ap) 用于將存放可變參數(shù)字符串的變量清空(賦值為NULL).

va_start的功能是要把,ap指針指向可變參數(shù)的第一個(gè)參數(shù)位置處,

#define_crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

先取第一個(gè)參數(shù)的地址,在sum函數(shù)中就是取number的地址并且將其轉(zhuǎn)化為char *的(因?yàn)閏har *的指針進(jìn)行加減運(yùn)算后,偏移的字節(jié)數(shù)才與加的數(shù)字相同, 如果為int *p,那么p+1實(shí)際上將p移動(dòng)了4個(gè)字節(jié)),然后加上4(__INITSIZEOF(number)=(4+3)&~3),這樣就將ap指向了可變參數(shù)字符串的第一個(gè)參數(shù)。

#define_INTSIZEOF(n) ( (sizeof(n) +sizeof(int) - 1) & ~(sizeof(int) - 1) )

以int所占的字節(jié)為標(biāo)準(zhǔn)進(jìn)行對(duì)其操作。

如果int占四字節(jié),則以四字節(jié)對(duì)齊為標(biāo)準(zhǔn)讀取數(shù)據(jù)。

va_arg是要從ap中取下一個(gè)參數(shù)。

#define_crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

對(duì)于這個(gè)宏,哥糾結(jié)了很久,最后終于搞清楚了,究其原因就是自己C語(yǔ)言功底不扎實(shí),具體表現(xiàn)在沒有搞清楚賦值表達(dá)式的值是怎么運(yùn)作的。

我們看這個(gè)宏,首先是ap = ap + __INTSIZEOF(t)。注意到,此時(shí)ap已經(jīng)被改變了,它已經(jīng)指向了下一個(gè)參數(shù),我們令x=ap + __INTSIZEOF(t);

那么括號(hào)內(nèi)就變成了(x – __INTSIZEOF(t)),但是這里沒有賦值運(yùn)算符,所以ap的值沒有發(fā)生變化,此時(shí)ap仍然指向的是當(dāng)前參數(shù)的下一個(gè)參數(shù)的位置,

也就是說(shuō)ap指向的位置比當(dāng)前正在處理的位置超前了一個(gè)位置。

其實(shí)寫成下面的形式就簡(jiǎn)單明了了:

#define?? va_arg(ap,t)?? (*(t?? *)((ap?? +=?? _INTSIZEOF(t)),ap?? -?? _INTSIZEOF(t)))

分析:為什么要將ap指向當(dāng)前處理參數(shù)的下一個(gè)參數(shù)了?

經(jīng)過(guò)上面的分析,我們知道va_start(ap,v)已經(jīng)將ap指向了可變參數(shù)列表的第一個(gè)參數(shù)了,以后我們每一步操作都需要將ap移動(dòng)到下一個(gè)

參數(shù)的位置,由于我們每次使用可變參數(shù)的順序是:va_start(ap,v)—>va_arg(ap,t);這樣我們?cè)诘谝淮稳?shù)的時(shí)候,其實(shí)ap已經(jīng)指向了

第二個(gè)參數(shù)開始的位置,所以我們用表達(dá)式的方式獲得一個(gè)指向第一個(gè)參數(shù)的臨時(shí)指針,這樣我們就可以采用這種一致的方式來(lái)處理可變參數(shù)列表。

(感覺沒表達(dá)的十分清楚,希望各位朋友糾正~~~~~~)。

下圖是我的例子程序中去參數(shù)的情況(時(shí)間倉(cāng)促,畫得很丑,請(qǐng)?jiān)彛?/p>

va_end(ap)? 將聲明的ap指針置為空,因?yàn)橹羔樖褂煤笞詈笤O(shè)置為空。

參考資料:

http://topic.csdn.net/u/20110830/15/a3630fc4-3c5f-4a1e-bbee-949ba7b4cbe0.html

http://topic.csdn.net/u/20070120/12/e8b7363b-6404-4d91-9307-01e5ed996f3d.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容