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 }