返回类型 函数名(已知类型,个数的参数列表,Type parmN,...);数组
parmN是最右边的已知类型的参数名;如:app
void f(int num,...) /** parmN就是"num" */
/** * 初始化ap,必须先于va_arg(),va_end(),va_copy被调用. * @param ap va_list类型变量. * @param parmN 见上 * @warning 因为须要parmN的地址来初始化ap,因此表达式'&(parmN)'应该是合法的,即 * parmN不能够是寄存器变量,数组,函数. * */ void va_start(ap,parmN)
/** * 返回下一个参数的值. * va_arg()宏展开后是一个表达式,该表达式的结果就是下一个参数的值.每一次调用都会更改ap的状态,从而完成遍历参数列表的工做 * @param ap va_start()初始过的va_list变量 * @param type 下一个参数的类型 * @warning 指向type类型变量的指针类型应该是'type *';如type可取int,double...可是type不能够是数组类型,函数类型 * @warning 受'默认实际参数提高'规则影响,type的值不多是: * char,unsigned char,signed char(若是指望参数类型为这些,则type是int) * short,unsigned short,unsigned short,short int,unsigend short int,signed short int(若是指望参数类型为这些,则type是int) * float(若是指望参数类型为这个,则type是double) * */ type va_arg(ap,type)
在调用一个不带原型声明的函数以前,编译器会对每一个实参执行"默认实际参数提高"后在传递给函数。具体规则以下函数
char、short和相应的signed、unsigned类型的实际参数提高到int,若是int不能存储原值,则提高到unsigned intspa
float类型的实际参数将提高到double指针
一样在调用具备可变参数列表的函数时,也会运用'参数提高规则',因此在函数内部是不会出现char,short,float类型的参数的!因此Type的值不多是...code
/** 在结束对可变参数列表的遍历后调用 */ va_end(ap)
在调用va_start()对ap进行初始化以后,能够在函数中或者她调用的其余函数中执行va_arg()遍历可变参数原型
/** * 遍历并打印可变参数列表. * @param num 可变参数列表中参数个数 * @param ap 由调用者传递,ap中存放若干个int类型的参数 */ void printArgs(int num,va_list ap){ printf("Begin...\n"); while(--num >= 0) printf("%d\t",va_arg(ap,int)); printf("\nOver...\n"); return ; } void f1(int num,...){ va_list ap; va_start(ap,num); printArgs(num,ap); // printArgs(num,ap);/* 能够验证ap的状态被改变了 */ va_end(ap); return ; }
如上在printArgs()中因为使用了va_arg因此会更改ap的状态,那么在f1调用printArgs()以后f1中的ap的状态是否会变化?编译器
根据对va_list实现的不一样,ap可能采用传值或者传址调用,即没法保障f1中ap必定不变it
如上函数,运行后f1中ap的状态被改变了io
/** * copies the (previously initialized) variable argument list src to dest. * 行为就像: * va_start(des,parmN); * [va_start() were applied to dest with the same last argument] * 若干次的va_arg(des,type)调用 * [followed by the same number of va_arg() invocations that was used to reach the current state of src.] * */ void va_copy(va_list des,va_list src);
void printArgs(int num,va_list ap){ va_list xap; va_copy(xap,ap); /* 执行一次copy操做 */ printf("Begin...\n"); while(--num >= 0) printf("%d\t",va_arg(xap,int));/* 使用xap遍历参数列表,不会改变ap的状态 */ printf("\nOver...\n"); va_end(xap); return ; } void f1(int num,...){ va_list ap; va_start(ap,num); printArgs(num,ap); printArgs(num,ap);/* 能够验证ap的状态不会被改变 */ va_end(ap); return ; }
void printArgs(int num,va_list *ap){ /* 传递ap的地址 */ printf("Begin...\n"); while(--num >= 0) printf("%d\t",va_arg(*ap,int)); /* 解引用 */ printf("\nOver...\n"); va_end(*ap); return ; } void f1(int num,...){ va_list ap; va_start(ap,num); printArgs(num,&ap); printArgs(num,&ap); va_end(ap); return ; }