可变参数函数
计算机科学术语
在计算机程序设计,一个可变参数函数是指一个函数拥有不定引数,即是它接受一个可变数目的参数。简单来说,就是函数的参数个数可变,参数类型不定的函数。
简介
在计算机编程时,可变参数函数中参数是一个可变数目,即这个函数拥有不定引数。
一般而言,在设计函数时会遇到许多数学逻辑操作,是需要一些可变功能。例如,计算数字串的总和、字符串的联接或其他操作过程,都可以存在任意数量的参数。
另一种许多语言都实现为可变参数函数的是格式输出函数,在C语言的printf函数和Common Lisp的format函数就是例子。这些函数都需要一个参数,指定格式的输出,再读取可变参数的值进行格式化。
另外,可变参数函数在某些语言存在安全问题。例如C语言在没有长度检查和类型检查,在传入过少的参数或不符的类型时可能会出现溢位的情况,更可能会被利用为攻击目标。所以,在设计函数时可以先考虑其他替补方案,例如以类型安全的方式——重载
C/C++中的举例
在C语言中,C标准函式库的stdarg.h标头档定义了提供可变参数函数使用的。在C++,应该使用标头档cstdarg。
要创建一个可变参数函数,必须把省略号(...)放到参数列表后面。函数内部必须定义一个va_list变数。然后使用va_start、va_arg和va_end来读取。例如:
这个是一段计算平均数的程式码,可以输入任意数量的小数并计算平均数,注意计算以0停止计算。请注意,函数不知道参数的数量或它们的类型,这里要求的类型是double,而且第一个参数传递可变参数的数量。在另外的情况下,例如printf,参数的数量和类型都设定在格式字符串中。在这两种情况下,程序员实际上需要提供正确的参数,如果参数传递少了或参数的类型不正确,导致读入内存的无效区(溢位),这样会有安全漏洞如格式字符串攻击。
C++中可变参数的函数是从C中继承而来,可变参数的函数是指函数的参数个数可变,参数类型不定的函数。我们最常见的就是printf()。
可变参数函数实现原理
指定参数的函数实现很简单,通过通过指定的参数名访问就行了。但是如果不指定的呢?函数的调用的参数会进行压栈处理。而对参数的压栈是从右到左进行压栈。而参数和参数之间存放是连续的,也就是说,只要知道第一个参数的地址和类型,以及其他参数的类型,就可以获取各个参数的地址。
比如:
函数调用内存结构如右:
这里的a是int型,b是char型。printf()有3个参数,一个const char*,一个是int,一个是char。所以参数压栈的顺序就是先将b入栈,再将a入栈,最后是format入栈,由于是向下(低地址)生长的,所以在知道了format的地址之后,所有的参数地址都可以计算出来。
声明和定义
可变参数函数的声明很简单,对于不定参数部分用“...”表示即可。但是实现原理可以看到,第一个的参数的地址是必须提供的,也就是可变参数必须至少包含一个参数,这个参数用来寻址,实现对所有参数的访问。
当然通常也会在对第一个参数进行一些特殊处理以方便函数的实现,比如强制指定为参数个数,或者像printf一样使用格式占位符来。
C++11/C++14中的举例
C++11新增了initializer_list物件,当编译器遇到大括号阵列变成函数的参数时,会自动将大括号阵列转型成initializer_list物件,因此可以使用此原理来做出“相同型别”参数的可变参数函数。
JavaScript中的举例
在JavaScript(简称js)中,函数的可变参数用法很巧妙。
参考资料
最新修订时间:2024-07-02 09:41
目录
概述
简介
参考资料