阶段总结3---可变参数列表

    在函数的原型中,列出了函数期望接受的参数,但是原型只能显示固定数目的参数。有时候我们需要让一个函数在不同的时候接受不同数目的参数,这就需要用到可变参数列表。部分同学可能不知道其实我们大多数在刚学C语言时就接触到了可变参数的函数,即printf(),但是它具体是如何实现的呢?

    先附上两个关于可变参数列表的练习题:

https://blog.csdn.net/Wing_Ming/article/details/80275964

   可变参数列表通过宏来实现的,这些宏定义于stdarg.h头文件,它是标准库的一部分。这个头文件声明了一个类型为va_list、va_arg和va_end。我们可以声明一个类型为va_list的变量,与这个宏配合使用,访问参数的值。

在VS的源码中我们可以看到:

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)

注意参数列表的中得省略号:它提示此处可能传递数量和类型未确定的参数。在编写函数原型时也要用相同的记法。

   函数声明了一个名叫var_arg的变量,它用于访问参数列表的未确定的部分。这个变量通过调用va_start来初始化。它的第1个参数是va_list变量的名字,第2个省略号前最后一个有名字的参数。初始化过程把var_arg变量设置为指向可变参数列表的部分的第1个参数。

   为了访问参数,需要使用va_arg,这个宏接受两个参数:va_list变量和参数列表中下一个参数的类型。在这个例子中,所以的可变参数都是整数。在有些函数中,你可能要通过全面获得的数据来判断下一个参数的类型。Va_arg返回这个参数的值,并使用var_arg指向下一个可变参数。

   最后,当访问完毕最后一个可变参数之后,我们需要调用va_end。

 

可变参数的限制:

   注意:可变参数必须从头到尾按照顺序逐个访问。如果你在访问了几个可变参数后想半途终止,这是可以的。但是,如果你想一开始就访问参数列表中间的参数,那是不行的。另外,由于参数列表中的可变参数部分并没有原型,所以,所有作为可变参数传递给函数的值都将执行缺省参数类型提升。

 

   你可能同时注意到参数列表中至少要有一个命名参数。如果连一个命名参数也没有,你就无法使用va_start。这个参数提供了一种方法,用于查找参数列表的可变部分。

   注意:如果在va_arg中指定了错误的类型,那么其结果是不可预测的。这个错误很容易发生,因为va_arg无法正确识别作用于可变参数之上的缺省类型提升。char、short和float类型的值实际上将作为int或double类型的值传递给函数。所以在va_arg中使用后面这些类型时应当注意。




你可能感兴趣的:(阶段总结3---可变参数列表)