函数不定参数个数的实现

1. C语言函数的调用方式 _cdecl 调用

_cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈所以在函数调用栈中, 越右边的参数在栈的越低端,既内存地址越大。

2.实现

函数如何实现不定参数:由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载。对这种情况,提出了指针参数来解决问题。

(1)va_list

  定义了一个指针arg_ptr, 用于指示可选的参数.

(2)va_start(arg_ptr, argN)

  使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,argN是位于第一个可选参数之前的固定参数,

  或者说最后一个固定参数.如有一va 函数的声明是void va_test(char a, char b, char c, ...), 则它的固定参数依次是a,b,c, 最后一个固定参数argN为c, 因此就是va_start (arg_ptr, c).

(3)va_arg(arg_ptr, type)

  返回参数列表中指针arg_ptr所指的参数, 返回类型为type. 并使指针arg_ptr指向参数列表中下一个参数.返回的是可选参数, 不包括固定参数.

(4)va_end(arg_ptr)

  清空参数列表, 并置参数指针arg_ptr无效.

  (注:va在这里是variable-argument(可变参数)的意思.   这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件)

过程:

调用va_start()后parg将指向第一个不固定的参数,在这个函数中也就是v2后面的参数。

接着调用va_parg():va_parg同样接受两个参数第一个参数是经过va_start()处理过后的parg指针。

第二个参数是期望不固定参数的类型,编译器无法确定可变参数的类型,但是必须这么做。

va_parg返回parg当前指向的那个可变的参数。并且每次调用都会更新这个指针,使得parg向下个参数移动;

最后调用va_end():va_end接受一个参数,parg,他会将parg重置为NULL;没用调用va_end函数将无法运行。

3.举例

(1)固定参数个数(2个)

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

int print(const char *format, ...)
{
    va_list args;
    const char *args1;
    va_start(args, format);
    args1 = va_arg(args,const char *);
    va_end(args);
    printf("format=%s args1=%s", format, args1);
}
int main()
{
    print("11111", "22222");
}

运行结果:

format=11111 args1=22222

(2)多个参数(采用循环)

double average(double v1, double v2, ...){
    va_list parg;
    //将parg指向第一个不固定的参数
    va_start(parg, v2);
    double sum = 0.0;
    sum = v1 + v2;
    double value;
    int count = 2;
    //va_arg判断下一个不固定参数类型是否为double
    while((value = va_arg(parg, double)) != 0.0){
        sum += value;
        ++count;
    }
    va_end(parg);
    return sum/count;
 
}


4.注意

va_arg(ap,type)中的type绝对不能为以下类型:
——char、signed char、unsigned char
——short、unsigned short
——signed short、short int、signed short int、unsigned short int
——float

 

参考:

https://www.cnblogs.com/linhaostudy/p/6695422.html

https://blog.csdn.net/wabil/article/details/72800624?utm_source=blogxgwz0

https://blog.csdn.net/bristar_zon/article/details/48465021

https://blog.csdn.net/qq_25367755/article/details/50946574

posted @ 2018-11-08 11:32  小时候挺菜  阅读(1794)  评论(0编辑  收藏  举报