如何编写可以处理多个参数的函数声明,如printf()
换句话说,我可以通过多种方式调用该函数
Func(Var,12,False);
或Func(Var,12,14,False);
或Func(Var1,Var2,12,14,False);
等。
怎么做?感谢。
答案 0 :(得分:8)
如评论所述,它被称为varargs(variadic参数),请参阅va_arg(3)手册页。
但是,请注意,您的函数应该知道,至少在运行时它有多少个参数以及每个参数的类型。从您的示例中可以看出这一点。
给出你的例子:
Func (Var, 12, False);
Func (Var, 12, 14, False);
Func (Var1, Var2, 12, 14, False);
我甚至无法猜出上述调用的区别。让我们假设我们宣布了
int Var; // Var is an integer
double Var1; // Var1 is a double-precision floating point
char* Var2; // Var2 "is" a string
然后,从Func
的实现者的角度来看,我看不出你的不同调用的区别。也许你应该接受给Func
一个额外的第一个常量字符串参数(比如例如printf(3))描述其他参数的数量和类型,所以将你的例子改为:
Func("iib", Var, 12, false);
Func("iiib", Var, 12, 14, false);
Func("dsiib", Var1, Var2, 12, 14, False);
使用约定(你应该文档),Func
的第一个参数是一个描述其他参数类型的常量字符串。 i
参数为int
,b
参数为bool
,d
为double
,s
为char*
(你会声明:
void Func(const char*, ...);
另一种可能的约定将为每个参数添加一些枚举值:
enum kindarg_en { EndArg, BoolArg, IntArg, DoubleArg, StringArg };
然后你的电话就变成了
Func (IntArg, Var, IntArg, 12, BoolArg, false, EndArg);
Func (IntArg, Var, IntArg, 12, IntArg, 14, BoolArg, false, EndArg);
Func (DoubleArg, Var1, StringArg, Var2, IntArg, 12, IntArg, 14,
BoolArg, false, EndArg);
以上当然是C语言。对于C ++(尤其是C++11),您可以以不同方式设计所有内容(使用function overloading或variadic templates等等。)。
在C中,您应该确保可以在运行时确定参数的数量和类型(并且第一个参数应该具有某种固定类型)。 您应该有一些关于参数的实际数量和类型的文档约定。它甚至可能更难看(例如设置描述后续调用签名的全局变量)。
请注意,可变函数往往过时了。在20世纪80年代或90年代(甚至今天在32位x86 calling conventions上,但不在x86-64上)参数在堆栈上传递,而<stdarg.h>
中的设施只是简单地实现(通过递增堆栈指针,例如在非便携式汇编代码中)。在当前ABI - s上,特别是x86-64 ABI(对于Linux上的64位x86处理器),事情要复杂得多,可变函数(即va_start
....)需要深度编译器支持;在GCC上你有varargs builtins用于此目的(所以stdarg.h
是由编译器提供的。)
最后注意到GCC提供了一些特定的扩展来帮助类型化检查可变参数函数调用。至少,考虑使用一些function attributes(例如format
如果你声明一个类似printf
的函数,或sentinel
如果最后一个参数应该为零或null。 )。如果您更有野心(例如,如果您正在为其他人开发库,并具有一些重要的可变参数功能),则可以使用您自己的属性自定义GCC ,方法是使用MELT -a扩展GCC使用C ++手动编码的GCC插件扩展GCC的域特定语言或更痛苦...对于MELT,来自melt-examples的(未完成)ex06
示例说明了如何键入一些jansson调用:因此,当对可变参数json_pack
的调用格式不正确时,编译器有时能够发出一些警告。
答案 1 :(得分:1)
您正在寻找varargs功能。
采用可变数量参数的C函数(vararg 函数)在语法上对调用者来说很方便,但C就是这样做的 很难确保安全。被叫方没有万无一失的方法 确定参数的数量甚至它们的类型。还有 没有类型信息供编译器在呼叫站点使用拒绝 糟糕的电话。
您可以在此处找到有关如何使用varargs的信息:Writing a ``varargs'' Function