可变参数列表

在c语言中,一般来说,函数的参数个数是确定的,并且是根据我们的需要传入指定的参数,但在某些情况下,我们需要可变的参数列表来实现某些功能,因此c语言引入可变参数列表。具体的函数有printf函数,scanf函数等。

一可变参数列表的实现
为了实现可变参数列表,我们通常要用到stdarg.h头文件下的几个函数:

void va_start(va_list ap, last); //va_start用来初始化参数列表t
ype va_arg(va_list ap, type); //va_arg用来获取参数列表中的一个参数,类型为type。
void va_end(va_list ap); //va_end用来清理参数列表。
void va_copy(va_list dest, va_list src); //va_copy用来拷贝参数列表
va_list用来存放参数列表的数据结构。

这些函数以宏的方式实现:

typedef char * va_list; //字符串指针
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1)& ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )

二.宏的具体作用
1.va_list

typedef char * va_list; //宏的定义char*重命名为va_last,使得va_list定义的指针变量可以访问到未知参数列表

va_list arg;//取自下面的例子
定义了一个char*类型的指针arg,arg指向参数列表。(之所以定义为char*,是为了能取到char类型的变量)

2.va_start

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )//初始化参数列表
 _INTSIZEOF(v)的作用是跳过最后一个已知变量v,ap取到未知参数列表的第一个参数,完成参数列表的初始化

va_list arg;
va_start(arg, pos);//取自下面的例子
pos即v,是指向已知参数列表的指针,va_start初始化了最后一个已知参数后面的所有参数。

3.va_arg

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )//取出当前参数
t是未知参数列表中参数的类型。
((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))的作用是使得每次调用va_arg都能使指针自动往后移动一位,本次对本参数访问的同事,下次可以访问到下一个参数。

switch (*pos)//取自下面的例子
{
case ‘s’:s = va_arg(arg, char*);//字符串
cout << s;
break;
case ‘c’:c = va_arg(arg, char);//字符
cout << c ;
break;
case ‘d’:d = va_arg(arg, int);//整型变量
cout << d ;
break;
case ‘%’:
break;
default:
cout <<*pos;
break;
}
pos++;
}
已知参数列表逐步右移,如果遇上%d%c%s,就分别将未知参数列表中的数据以相应的形式输出。
4.va_end

#define va_end(ap) ( ap = (va_list)0 )//清空参数列表
把指向参数列表的指针置为0,达到清理参数列表的目的

三.简单的例子
给出两个简单的例子,大家体验一下实现方式:

简单模拟实现printf
void myprintf(char*pos, ...)
{
    assert(pos);
    char*s = NULL;
    char c = 0;
    int d = 0;
    va_list arg;
    va_start(arg, pos);
    while (*pos)
    {
        switch (*pos)
        {
        case 's':s = va_arg(arg, char*);//字符串
            cout << s;
            break;
        case 'c':c = va_arg(arg, char);//字符
            cout << c ;
            break;
        case 'd':d = va_arg(arg, int);//整型变量
            cout << d ;
            break;
        case '%':
            break;
        default:
            cout <<*pos;
            break;
        }
        pos++;
    }
    va_end(arg);
}

int main()
{
    myprintf("%d%c%s", 1,'a' ,"bc");
    return 0;
}
#include<stdio.h>
#include<stdarg.h>

int MAX(int val, ...)
{
    va_list arg;
    va_start(arg, val);
    int max = 0, temp = 0;
    int i = 0;
    max = va_arg(arg, int);//因为va_arg没出现一次参数就往后移一个,所以把第一个参数拿下来用来比较
    for (i = 1; i < val; i++)
    {
        if ((temp = va_arg(arg, int))>max)
            max = temp;
    }
    return max;
}

int main()
{
    int max = 0;
    max=MAX(5, 1, 5, 3, 8, 1);
    printf("%d\n", max);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值