C/C++语言的可变长参数函数

  • A+
所属分类:编程开发

通常C语言函数定义是固定类型和数量的。那么有没有传递任意个数参数的方法呢?

常见函数

我们把参数个数可变,参数类型不定的函数称之为不定长参数函数或可变长参数函数。
比如printf()scanf()等就是这样一类可支持任意参数个数变量的函数,以下是printf的用法示例。

printf("%d",x);
printf("%f",y);
printf(“Hello my name is %s“, name);

函数原型

这是printf的函数原型:

int printf(const char *fmt, …)

注意它的第二个参数,"…"三个点。这是可变长参数函数的参数,它的数量是可变动的,它使用省略号来忽略之后的参数。在这里其实是做了一个占位符的作用。

虽然参数类型和数量可变,但也存在限制,在C/C++中,任何使用变长参数声明的函数都必须至少有一个指定的参数(又称强制参数),即至少有一个参数的类型是已知的,而不能用三个点省略所有参数的指定,且已知的指定参数必须声明在函数最左端。

错误申明

//下面这种声明是错误的
int func(...);       //错误
int func(...,int a); //错误

参数接收

那么,传进来了多个参数,如何去使用它呢。这里需要用到一个头文件stdarg.h,以下是要用到的宏。va在这里是variable-argument(可变参数)的意思。
va_list 型的变量声明,比如 va_list arg_ptr;

void va_start( va_list arg_ptr, prev_param );
//确定起始位置。通过形参中的已知参数。比如printf中的*fmt
type va_arg( va_list arg_ptr, type );
//得到下一个可变参数的值,type代表参数类型。每次调用va_arg都会改变arg_ptr值使得后续的参数值能被依次添加。
void va_end( va_list arg_ptr );
//将指针置为无效

那么读取的做法显然是通过va_start定位起始位置,然后用va_arg一个个读取下来,最后用va_end将指针置为无效。
在函数的参数中,第一个参数的作用就是定位起始位置,如果是play(…)这样,我们就无法定位起始位置了,所以这个写法在C语言中是不能通过编译的,不过C++可以编译。

示例代码

//一个示例代码:
#include 
#include "stdio.h"
#include "stdarg.h"
using namespace std;
void play(int n,...)
{
    va_list ps;
    int x=n;
    va_start(ps,n); //以固定参数的地址为起点确定变参的内存起始地址。
    for(int i=0;i
    {
        x=va_arg(ps,int); //得到下一个参数的值
        printf("the %dth parameter is %d\n",i,x); //输出占位符位置参数的值
    }
    va_end(ps); //将指针置为无效
    return;
}
int main(int argc, char* argv[])
{
    play(3,200,-1,8);
    return 0;
}

其它

函数重载

在C++中,函数重载提供了多种参数传递的解决办法,但参数数量类型依然需要明确。

参考

C/C++要点全掌握(六)——变长参数
Go语言的可变长参数函数

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: