C语言中的可变参数

时间:2022-10-11 17:06:28

首先了解一下什么是可变参数

C语言中的可变参数

1、C语言中的可变参数列表:C语言中有时候会遇到一些参数个数是可变的函数,像scanf,printf等,这些函数内部的参数列表都是可变的。通过将函数实现为可变参数的形式,使得函数可以接受1个以上的任意多个参数。(不固定)

如函数原型:scanf(const char * format,…);
解释:除了format以外,后面跟着的参数 个数,类型是可变的,用…作为一种占位符号。“…”称为可变参数列表,可以用来接受个数和类型不确定的参数。

再例如printf()是一个支持可变参数的函数,可以有多个参数。函数原型:int printf(const char *format,...)   省略号代表参数的个数是不固定的。

(1)可变参数列表在C语言中使用这样的三个宏(va_start,va_arg,va_end)和一个类型(va_list)来进行实现的,他们是定义在stdarg.h头文件中的。

1)va_start原型

void va_start(va_list ap,paramN);

  参数:va_list:存储参数的类型信息
       ap:可变参数列表地址
       paramN:确定的参数
    2)va_arg原型
       void va_arg(va_list ap,type);返回下一个参数的值
    3)va_end原型
       void va_end(va_list ap,type);关闭初始化的列表

使用方式:
   1) 使用va_list初始化可变参数列表
   2) 使用va_arg逐个获取参数值
   3)用va_end将可变参数列表清空

   可变参数列表的限制条件:至少有一个参数

先看一个例子: 
实现一个函数可以求任意个参数的平均值 
#include <stdio.h>
#include <stdarg.h>
int average(int n, ...)
{
va_list arg;
//创建一个字符指针变量va_list相当于字符指针char*
int i = 0;
int sum = 0;
va_start(arg, n);//用n的地址初始化arg
for (i = 0; i<n; i++)
{    //获取参数va_arg(va_list arg,type),一定要保证类型正确
sum += va_arg(arg, int);

return sum / n;
va_end(arg);//arg=NULL将arg置为空指针,是结束标志

int main()
{
int a = 1;
int b = 2;
int c = 3;
int avg1 = average(2, a, c);
int avg2 = average(3, a, b, c);
printf("avg1 = %d\n", avg1);
printf("avg2 = %d\n", avg2);
return 0;
}

看一下运行结果:

avg1=2

avg2=2


说明: 声明一个 va_list 类型的变量 arg ,它用于访问参数列表的未确定部分。这个变量是调用 va_start 来初始化的。它的第一个参数是 va_list 的变量名,第2个参数是省略号前最后一个有名字的参数。初始化过程把 arg 变量设置为指向可变参数部分的第一个参数。为了访问参数,需要使用 va_arg ,这个宏接受两个参数: va_list 变量和参数列表中下一个参数的类型。在这个例子中所有的可变参数都是整型。va_arg````返回这个参数的值,并使用 va_arg```指向下一个可变参数。最后,当访问完毕最后一个可变参数之后,我们需要调用 va_end  头文件<stdarg.h>提供了

遍历未知数目和类型的函数参数列表的功能。



2、实现可变参数的要点就是想办法取得每个参数的地址,取得地址的办法由以下几个因素决定:

①函数栈的生长方向

②参数的入栈顺序

③CPU的对齐方式

④内存地址的表达方式



3、可变参数的限制 :

  • 可变参数必须从头到尾逐个访问。如果你在访问了几个可变参数之后想半途终止,这是可以的,但是,如果你想一开始就访问参数列表中间的参数,那是不行的。
  • 参数列表中至少有一个命名参数。如果连一个命名参数都没有,就无法使用va_start
  • 这些宏是无法直接判断实际存在参数的数量。
  • 这些宏无法判断每个参数的是类型。
  • 如果在va_arg中指定了错误的类型,那么其后果是不可预测的。