C 语言的可变参数表函数的设计

大多数时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的所有实际参数。但在某些情况下希望函数的参数个数可以根据需要确定。典型的例子有大家熟悉的函数printf()、scanf()等

  可变参数的实现:
  C语言头文件stdarg.h提供了一个数据类型va-list和三个宏(va-start、va-arg和va-end),va—start使vp指向第一个可选参数。va—arg返回参数列表中的当前参数并使vp指向参数列表中的下一个参数。va—end把vp指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va—start开始,并以va—end结尾。用它们在
被调用函数不知道参数个数和类型时对可变参数表进行测试,从而为访问可变参数提供了方便且有效的方法。va-list是一个char类型的指针,当被调用函数使用一个
可变参数时,它声明一个类型为va-list的变量,该变量用来指向va-arg和va-end所需信息的位置。
下面给出va_list在C中的源码:  

     typedef char * va_list; 

  采用ANSI标准形式时,参数个数可变的函数的原型声明是: 

   type funcname(type para1, type para2, ...) 

  这种形式至少需要一个普通的形式参数,后面的省略号不表示省略,而是函数原型的一部分,type是函数返回值和形式参数的类型。

  调用者在实际调用参数个数可变的函数时,要通过一定的方法指明实际参数的个数,例如把最后一个参数置为空字符串。
  
  下面给出一个具体的例子:
求n个数的和:

int Sum(int n,...)
{
    int i = 0,sum = 0;
    va_list vp; 
    va_start(vp,n); //va—start使vp指向第一个可选参数
    for (i=0; i<n; i++)
    {
        sum +=va_arg(vp,int); 
    }
    va_end(vp); //va—end把vp指针清为NULLreturn sum;
}

printf函数实现(此处只实现了基本类型的打印)

void my_print(const char *format,...)
{
    char c = 0;
    va_list vp; 
    va_start(vp,format); //vp指向第一个可选参数
    while (*format)
    {
        c = *format;
        switch (c)
        {
        case '%':
            {
                char cc = *(++format);
                switch (cc)
                {
                case 'd':
                    {
                        char str[50];
                        int  n = va_arg(vp,int); //va—arg返回参数列表中的当前参数并使vp指向参数列表中的下一个参数。
                        char *string = _itoa(n,str,10); //把整数转为字符串
                        print_str(string);
                    }
                    break;
                case 'f':
                    {
                        char str[50];
                        double f = va_arg(vp,double);//va—arg返回参数列表中的当前参数并使vp指向参数列表中的下一个参数
                        char *string = _gcvt(f,10,str);//将浮点型数转换为字符串,取四舍五入
                        print_str(string);
                    }
                    break;
                case 'c':
                    putchar(va_arg(vp,char));
                    break;
                case 's':
                    {
                        char *string = va_arg(vp,char*);
                        print_str(string);
                    }
                    break;
                default:
                    break;
                }
            }
            break;
        default:
            putchar(c);
            break;
        }
        format++;
    }
    va_end(vp); //va—end把vp指针清为NULL。
}

要明白可变参数必须知道函数调用过程(栈帧的创建与销毁),此内容在前面的博文中有详细介绍,文章地址:函数调用过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙跃十二

写的不错,给点鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值