我想调用一个函数(这里简称为 function ),该函数接受可变的参数列表,而无需事先知道需要多少个参数。 我想出了这个:
int param_num
char **param // initialized and populated somewhere else
...
if (param_num == 0) result = function();
else if (param_num == 1) result = function(param[0]);
else if (param_num == 2) result = function(param[0],param[1]);
...
以上代码仅是概念证明,并不旨在被编译。实际功能至少具有一个固定参数。我不能更改该函数,因为它属于外部库。实际的代码更加复杂,并且可以按预期工作,但是...
我的问题是:是否有一种更紧凑的方式来编写相同的代码而不接触“功能”?
PS在Linux上使用gcc 7
PPS只是好奇。我没有试图解决的真正问题。上面的代码按预期工作。只是想知道是否有办法使它更漂亮。
谢谢
答案 0 :(得分:3)
了解有关<stdarg.h>
and variadic functions的信息。在Linux上,另请参见stdarg(3)。这就是您如何在C中定义此类可变变量函数(例如printf
)的方法。前几个参数应该是固定的并且是已知类型的,因此您无法确切拥有所需的内容(使用function()
之类的调用而没有参数)。因此,要求一个可变参数函数必须至少具有一个第一个固定类型参数(通常确定其后可变参数的类型和数量,例如printf
)。因此,C语言规范禁止在没有任何参数的情况下调用带有两个参数的 same function
。
还要注意系统的ABI。它定义了calling conventions(通常随调用函数的签名而异)对于Linux上的64位x86,请参见this(浮点和指针参数在不同寄存器中传递)。
GCC(具体来说)还内置了constructing function calls,但是C11标准n1570却没有这样的东西。
目前尚不清楚您确切想要实现什么,但是在某些情况下,您可能会在运行时生成代码(例如,花哨地使用metaprogramming)。有几种方法可以在Linux上实现此目标:
您可以在/tmp/emittedcode.c
中生成(文件)一些C代码,将其编译作为插件(通过运行gcc -fPIC -shared -Wall -O -g /tmp/emittedcode.c -o /tmp/generatedplugin.so
),然后使用dlopen(3)加载该插件(像void*dlh = dlopen("/tmp/generatedplugin.so", RTLD_NOW);
一样,但您应该在那里处理故障)和dlsym(3)个符号。我的manydl.c示例显示,您实际上可以对数十万个生成的插件执行此操作。
您可以使用一些JIT-compiling库,例如libgccjit或asmjit或libjit或GNU lightning等...
在两种情况下,您都将(在概念上)将新的code segment添加到您的process并将新创建的函数的地址存储到某个function pointer中。
还要注意closures和anonymous functions,并注意C没有它们(但必须使用callbacks)。阅读SICP。
正如Antti Haapala所评论的那样,也请研究libffi(它使您可以通过“解释”调用带有任意参数的任意函数,该调用将由临时数据结构描述)
答案 1 :(得分:0)
如果您确切地知道需要传递哪种类型的args,则可以创建一个其中定义了可能的args的结构
然后您可以通过结构并完成您的工作
struct args {
define args....
}
.
.
struct args* a;
result = function(a);
请记住,您必须在函数中添加一些检查以查看传递了哪些args。