1 /*my_stdarg.h*/ 2 /* 3 * c容許定義可接受一個可變參數列表的函數。並且是本身定義的額外的函數。 4 * stdarg.h定義的宏。容許在任什麼時候候從頭至尾地便利一個附加參數列表。 5 * 在遇到每個參數以前,必須知道它的類型,但在一個給定的調用發生以前,沒必要知道它的細節。 6 * 宏va_start,一個函數必須至少聲明一個固定的參數。宏va_start引用了最後一個固定參數因此它可以對可變參數進行定位, 7 * 訪問全部未命名的參數以前調用宏。對類型va_list ap初始化。 8 * 宏va_arg,每一次調用都會修改ap,每次調用這個宏展開的表達式的類型和值跟調用的下一個參數的相同。 9 * 第一次調用返回parmN後面的第一個參數。 10 * 宏va_end,一個函數在返回到它的調用者以前必定要調用va_end。 11 * stdarg.h聲明瞭一種類型,定義了3個宏,這樣就能夠提早訪問一個參數表,調用函數在編譯時並不知道這個參數表中參數的數目和類型。 12 * 在...以前的那個參數起着特殊的做用,記做parmN。 13 * 聲明類型va_list。 14 * 可重複使用。 15 * 16 * 17 * c標準定義,一個可變參數表在內存中佔據了一個連續的字符數組; 18 * 後繼的參數佔據着字符數組更高爲位。 19 * 一個參數佔據的空間開始於2^N字節的整數倍的存儲邊界。 20 * 存儲空間的大小是能夠表示這個參數2^N字節的最小倍數。 21 * 存儲空間留下的任何間隙老是在參數數據對象的開頭或者結尾。 22 * 23 */ 24 25 #define _AUPBND 3/*在可變參數表內部肯定存儲邊界的屏蔽宏,2^N-1*/ 26 #define _ADNBND 3/*肯定存儲空隙是否在一個參數數據對象的開端或者結尾的屏蔽宏,在尾處2^N-1,不然爲0*/ 27 /*4倍數對齊,且結尾爲開始出,則 3 0*/ 28 #ifndef MY_STDARG_H_ 29 #define MY_STDARG_H_ 30 /*保存一個指向下一個參數空間的起始位置的指針*/ 31 typedef char *va_list; 32 /* 33 * 經過增長va_list對象ap的內容來使它指向下一個參數空間的起始位置,而後再退回來指向當前參數的起始位置, 34 * 而後經過強制類型轉換把這個指針值轉換成爲指定類型的指針,最後解引用這個指針以訪問存儲在數據對象中的值。 35 */ 36 #define va_arg(ap, T) (*(T *)(((ap) += _Bnd(T, _AUPBND)) - _Bnd(T, _ADNBND))) 37 /*佔位符*/ 38 #define va_end(ap) (void)0 39 /*跳過已命名的參數,也就是最後一個固定參數,使用內部宏_Bnd把它的參數大小操做爲2^N字節的一個倍數*/ 40 #define va_start(ap, A) (void)((ap) = (char *)&(A) + _Bnd(A, _AUPBND)) 41 #define _Bnd(X, bnd) (sizeof(X) + (bnd) &~ (bnd)) 42 #endif
1 /*my_stdarg.c*/ 2 #include <assert.h> 3 #include <stdio.h> 4 #include "my_stdarg.h" 5 6 typedef struct { 7 char c; 8 }cstruct; 9 10 static int tryit(const char *fmt, ...) 11 { 12 int ctr = 0; 13 va_list ap; 14 15 va_start(ap, fmt); 16 for(; *fmt; ++fmt) 17 switch(*fmt){ 18 case 'i': 19 assert(va_arg(ap, int) == ++ctr); 20 break; 21 case 'd': 22 assert(va_arg(ap, double) == ++ctr); 23 break; 24 case 'p': 25 assert(va_arg(ap, char *)[0] == ++ctr); 26 break; 27 case 's': 28 assert(va_arg(ap, cstruct).c == ++ctr); 29 } 30 va_end(ap); 31 return ctr; 32 } 33 int main(void) 34 { 35 cstruct x = {3}; 36 37 assert(tryit("iisdi", '\1', 2, x, 4.0, 5) == 5); 38 assert(tryit("") == 0); 39 assert(tryit("pdp", "\1", 2.0, "\3") == 3); 40 printf("sizeof(va_list) == %u\n", sizeof(va_list)); 41 puts("success testing stdary.h"); 42 return 0; 43 }