閱讀目錄(Content)
《OOC》筆記(3)——C語(yǔ)言變長(cháng)參數va_list的用法
C語(yǔ)言中赫赫有名的printf函數,能夠接受的參數數目不固定,這就是變長(cháng)參數。C#里也有params這個(gè)關(guān)鍵字用來(lái)實(shí)現變長(cháng)參數。
1 printf("Hello Mozart!");2 printf("Hello %s!", "Mozart");3 printf("%d: Hello %s!", 77, "Mozart");
舉例如下。
1 #include <stdarg.h> 2 3 int add(const char * testString, int x, ...) 4 { 5 printf("%s\n", testString); 6 va_list list; 7 va_start(list, x); 8 int result = 0; 9 10 for(;;)11 {12 int p = va_arg(list, int);13 if(p == 0)14 break;15 result += p;16 }17 va_end(list); // cleanup , set 'lsit' to NULL18 return result;19 }20 21 /* error: ISO C requires a named argument before '...'22 void add2(...)23 {24 }25 */26 27 int main()28 {29 int result = add("test case 1: ", 1, 2, 3, 4, 5, 0);30 printf("%d\n", result);31 system("PAUSE");32 return 0;33 }34 35 /*36 This program print as follows:37 test case 1: 38 1539 */
編寫(xiě)使用變長(cháng)參數的函數步驟如下。
注意,在"..."前面至少要有一個(gè)普通的參數。(可能非標準C不需要,不過(guò)我們還是保守一點(diǎn)最好)
va_list類(lèi)型的list變量可以遍歷"..."中的參數。
用va_start()來(lái)初始化list變量。va_start()需要挨著(zhù)"..."的左邊那個(gè)參數名。(示例中的x)
va_arg()用于獲取下一個(gè)參數值。這個(gè)參數值的類(lèi)型你必須在編碼時(shí)就能確定。
va_end()用于結束對list的遍歷。之后你可以再次使用va_start()、va_arg()、va_end()來(lái)依次獲取各個(gè)可變參數值。
在add這個(gè)示例中,最后一個(gè)參數必須為0,add才能知道可變參數處理完畢。沒(méi)有別的辦法。也就是說(shuō),你不可能通過(guò)任何方式不借助外力就得知傳進(jìn)來(lái)的可變參數到底有幾個(gè)。
在printf("%d, %s, %c", 1, "11", '1');函數中,printf會(huì )分析格式化參數"%d, %s, %c",它看到3個(gè)格式化輸出符號,所以就認為傳入了3個(gè)可變參數。如果你傳入的多了或者少了,程序就可能出錯。編譯器無(wú)法檢測這個(gè)錯誤。
list變量可以作為參數傳遞給其它函數。(如vprintf("xxx", list);)
在傳遞可變參數時(shí),整型會(huì )作為int或long傳遞,float型會(huì )作為double傳遞。
va_arg()的第二個(gè)參數(示例中的int)不應太復雜。(這話(huà)很含糊)
總之,C語(yǔ)言中使用變長(cháng)參數不是什么好的編程實(shí)踐。能避免盡量避免。
typedef char* va_list#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)
va_list是在stdio.h中定義的類(lèi)型。va_start、va_arg、va_end是三個(gè)宏定義。
va_start把((v的地址)+(v的長(cháng)度))賦給list。根據函數調用時(shí)形參的內存布局,這樣list就指向了第一個(gè)可變參數。(示例中的2)
每次調用va_arg都會(huì )獲得當前參數值,并將ap指針指向下一個(gè)參數。
調用va_end會(huì )將ap重置為0。
所以這個(gè)可變參數的原理就是一個(gè)迭代器,它在函數棧的參數上移動(dòng)以依次獲取可變參數。
聯(lián)系客服