如何编写一个可以处理C中多个参数的函数声明?

时间:2013-12-07 07:08:56

标签: c

如何编写可以处理多个参数的函数声明,如printf()

换句话说,我可以通过多种方式调用该函数

  • Func(Var,12,False);

  • 或Func(Var,12,14,False);

  • 或Func(Var1,Var2,12,14,False);

  • 等。

怎么做?感谢。

2 个答案:

答案 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参数为intb参数为boolddoubleschar*(你会声明:

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 overloadingvariadic 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