可变参数函数

函数声明:

  • 返回类型 函数名(已知类型,个数的参数列表,Type parmN,...);数组

  • parmN是最右边的已知类型的参数名;如:app

void f(int num,...)
/** parmN就是"num" */




va_start

/**
 * 初始化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

/**
 * 返回下一个参数的值.
 * 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


/** 在结束对可变参数列表的遍历后调用 */
va_end(ap)

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

确保不被共享

va_copy


/**
 * 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 ;
}
相关文章
相关标签/搜索