可变参数函数
在计算机程序设计,一个可变参数函数是指一个函数拥有不定引数,即是它接受一个可变量目的参数。不同的编程语言对可变参数函数的支持有很大差异。
一般而言,在设计函数时会遇到许多数学和逻辑操作,是需要一些可变功能。例如,计算数字符串的总和、字符串的联接或其他操作过程,都可以存在任意数量的参数。
另一种许多语言都实现为可变参数函数的是格式输出函数,在C语言的printf
函数和Common Lisp的format
函数就是例子。这些函数都需要一个参数,指定格式的输出,再读取可变参数的值进行格式化。
另外,可变参数函数在某些语言存在安全问题。例如C语言在没有长度检查和类型检查,在传入过少的参数或不符的类型时可能会出现溢出的情况,更可能会被利用为攻击目标。所以,在设计函数时可以先考虑其他替补方案,例如以类型安全的方式——重载。
例子
[编辑]C/C++
[编辑]在C语言中,C标准函数库的stdarg.h头文件定义了提供可变参数函数使用的宏。在C++,应该使用头文件cstdarg。
要创建一个可变参数函数,必须把省略号(...)放到参数表表后面。函数内部必须定义一个va_list
变量。然后使用宏va_start
、va_arg
和va_end
来读取。例如:
#include <stdio.h>
#include <stdarg.h>
double average(int count, ...); /* 函数声明,计算参数的平均值。直到参数为0时停止计算 */
int main(void) /* 测试代码 */
{
double avg;
avg = average(3, 2, 1, 5, 0);
printf("%f\n", avg);
return 0;
}
double average(int count, ...)
{
va_list ap;
int i, cnt = 0; /* cnt 表示参数个数 */
double tot = 0; /* 参数的和 */
va_start(ap, count);
for (i = count; i; i = va_arg(ap, int), cnt++) /* i为当前获取参数的值 */
tot += i;
va_end(ap); /* 将参数列表清空 */
return tot / cnt;
}
这个是一段计算平均数的代码,可以输入任意数量的小数并计算平均数,注意计算以0停止计算。请注意,函数不知道参数的数量或它们的类型,这里要求的类型是double
,而且第一个参数传递可变参数的数量。在另外的情况下,例如printf
,参数的数量和类型都设置在格式字符串中。在这两种情况下,程序员实际上需要提供正确的参数,如果参数传递少了或参数的类型不正确,导致读入内存的无效区(溢出),这样会有安全漏洞如格式字符串攻击。
C++允许函数重载。对于重载函数,有省略符的可变参数函数的匹配优先级最低。只有其它重载函数都不能匹配时,才会与候选的可变参数函数匹配。
C++11/C++14
[编辑]C++11新增了initializer_list对象,当编译器遇到大括号数组变成函数的参数时,会自动将大括号数组转型成initializer_list对象,因此可以使用此原理来做出“相同类型”参数的可变参数函数。
#include <iostream>
using namespace std;
template<typename T>
T sum(initializer_list<T> il) {
T data(0);
for (T i : il)
data += i;
return data;
}
int main() {
cout << sum( { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }) << endl;
return 0;
}
JavaScript
[编辑]在JavaScript(简称js)中,函数的可变参数用法很巧妙。
function test(){
// 不管函数是否声明参数,所有的参数都会添加到arguments中,arguments以数组的形式将参数保存起来
var params = arguments;
// 以数组的形式输出
console.log(params);
};
test("a");// 结果:["a"]
test("a", 1);// 结果:["a", 1]
test("a", 1, function(){});// 结果:["a", 1, function (){}]
参见
[编辑]外部链接
[编辑]- Variadic function (页面存档备份,存于互联网档案馆). Rosetta Code task showing the implementation of variadic functions in over fifty programming languages.
- Variable Argument Functions — A tutorial on Variable Argument Functions for C++
- GNU libc manual (页面存档备份,存于互联网档案馆)