[C]va_list可变长参数的使用

一、概述

运用标准C的头文件stdarg.h提供的宏可以实现函数的自定义传参个数;

二、语法

1.va_list是一个可变长参数类型,在使用可变长参数的函数中可以定义1个或多个va_list类型参数,等待va_start初始化后使用;

va_list parg_1;
va_list parg_2;

2.va_start作用是给va_list类型变量绑定一个起始值

宏原型:

void va_start(va_list ap, last);

ap是va_list类型变量;

last是函数的最后一个固定参数(由于可变长函数的声明语法,参数部分必须至少包含一个固定传参);

va_start执行后,该ap的指针将会指向变参的起始位置;

3.va_copy作用是复制一份初始化后的va_list变量,通常用在调用va_start之后;

void va_copy(va_list ap2, va_list ap1);

ap2是复制到达的va_list变量;

ap1是被复制的va_list变量;

复制完毕后,两个变量的变长参数偏移量不相干;

4.va_arg被调用后将会返回当前指针偏移量的参数,随之指针将会移动到下一个变参的位置

type va_arg(va_list ap, type);

ap是被初始化后的va_list变量;

type是,除以下类型之外的其他类型

type绝对不能为以下类型:
——charsigned char、unsigned char
——short、unsigned short
——signed shortshort int、signed short int、unsigned short int
——float

这是因为C标准中有一个默认参数提升(default argument promotions)规则

注意:有时候因为代码问题(例如类型错误)导致va_arg返回了错误的结果,但是也不会影响va_arg的下一次取参哦,这是因为指针的偏移是通过变参的底层size属性获取的

5.va_end用于结束整个取参流程

void va_end(va_list ap);

二、示例

1.通过代码说明printf的原理

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

void myPrintf(const char *format, ...);
 
int main(void)
{
    char str_1[] = "January & February";
    double d_1 = 0.25;
    int i_1 = 16;
    char str_2[] = "March & April";
    int i_2 = 528;
    myPrintf(str_1, d_1, i_1, str_2, i_2);
}

void myPrintf(const char *format, ...)
{
    printf("%s\n", format);
    va_list parg;
    va_start(parg, format);
    printf("%.6lf\n", va_arg(parg, double));
    printf("%d\n", va_arg(parg, int));
    printf("%s\n", va_arg(parg, char*));
    printf("%d\n", va_arg(parg, int));
    va_end(parg);
}

输出:

0.250000

16

March & April

528

说明:

C自带的printf函数是根据第一个参数format的占位符解析出后面的变参个数和类型,通过va_arg迭代去获取变参再填充到占位符上输出。解析占位符并不是一件简单的工作,所以这里的代码只是大致说明了一下它的原理;

2.求平均数

#include <stdio.h>
#include <stdarg.h>


double average(double v1, double v2, ...);

int count = 0;

int main(void)
{
    printf("Average = %.6lf\n", average(0.2, 3.5, 108.625, (double)56, 0.3, 0.0));
}

double average(double v1, double v2, ...)
{
    va_list parg;
    double sum = v1 + v2;
    double value = 0.0;
    int count = 2;

    va_start(parg, v2);
    while((value = va_arg(parg, double)) != 0.0)
    {
        printf("Item = %.6lf\n", value);
        sum += value;
        ++count;
    }
    va_end(parg);
    return sum/count;
}

说明:

此代码在固定前两个参数的前提下,后面使用变参

 

posted @ 2018-08-07 11:01  yiyide266  阅读(660)  评论(0编辑  收藏  举报