![](/img/trans.png)
[英]Is it possible to call a function using a function pointer with number and type of arguments known only at runtime
[英]How do I call a function pointer where number of arguments if only known at runtime
在c中,请考虑这种情况。 我有一个函数指针数组,我想分别调用它们。 我也有一个整数数组,告诉我每个参数接受多少个参数。 第三,我想调用它们的参数数组。 以下程序是使用此程序的示例:
int foo(int a, int b, int c){
return a+b+c;
}
int bar(int a, int b){
return a+b;
}
int baz(int a){
return a;
}
int qux(){
return 0;
}
int main(){
void *funcArray[4] = {foo, bar, baz, qux}; //an array of function pointers, all of which return ints but have different numbers of arguments
int argArray[3+2+1+0] = {100,30,1, 20,7, 9}; //these are the arguments to the functions to be executed
int numArgsArray[4] = {3,2,1,0}; //these are the numbers of arguments that each function takes in the funcArray array
int nextArg = 0; //used to keep track of which argument goes to which function
for (int i = 0; i<4; i++){
int result;
switch(numArgsArray[i]){
case 0://if the function takes no args, just call it
result = ((int(*)())funcArray[i])();
break;
case 1://if the function takes one arg, pass it the argument when calling it
result = ((int(*)(int))funcArray[i])(argArray[nextArg]);
nextArg += 1;
break;
case 2://if the function takes two arguments, pass it both when calling
result = ((int(*)(int, int))funcArray[i])(argArray[nextArg], argArray[nextArg+1]);
nextArg += 2;
break;
case 3://if the function takes three args, pass it all three when calling
result = ((int(*)(int, int, int))funcArray[i])(argArray[nextArg], argArray[nextArg+1], argArray[nextArg+2]);
nextArg += 3;
break;
}
printf("%d\n", result);
}
return 0;
}
上面的程序起作用,并输出:131 27 9 0这是预期的输出。 问题是,我需要在switch语句中为每个要支持的参数数目添加一个大小写。 所以我的问题是:有没有一种更简单的方法来做到这一点,而且它并不那么丑陋,并且可以处理任意数量的参数?
如果可能的话,代替编写用于每个参数数量的单独函数,而是编写一个使用int
数组代替计数的函数,甚至考虑使用<stdarg.h>
但您仍然需要某种哨兵或计数。
否则,您将陷入语言标准本身无法保证的非便携式实现特定行为。
使用某些调用约定(例如, 在此处阅读x86示例) ,可以使用附加参数来调用该函数,而在正确使用相关的参数时,它们将在寄存器或堆栈中被忽略,然后由于原始堆栈指针被丢弃而被丢弃。在其他体系结构上,函数返回时调整堆栈指针的数量与函数参数的数量有关,因此上述方法将崩溃:如果您想阅读编译器/系统的约定并且有一个非-便携式解决方案,这是一个选择。
否则,再次取决于您的调用约定,您可能能够在调用函数之前使用汇编语言在堆栈上推送一些参数。 我已经在stackoverflow上看到过用代码执行此操作的问题,但是可能要花一些时间才能找到一个。 不过,您仍需要一个与您所使用的调用约定相对应的。
可以稍微改善一下:
typedef int (*FuncP)(); // function returning int and taking unspecified arguments
FuncP func_array[4] = { foo, bar, baz, qux };
// ...
// cast unnecessary
case 1:
result = funcArray[i](arg1);
如果您使用错误的数量或类型的参数调用函数,则会导致未定义的行为,但是,只要像您在代码中实际那样跟踪参数的数量,就可以很好地定义它。
没有比这更简单的方法来保留可移植性和功能。 在某些系统上,您会通过传递额外的伪参数来避免麻烦。
当然,您可以重写函数,以采用包含TonyD建议的可变长度参数列表的结构。 您还可以为每个带有固定参数列表的函数编写thunk,但这将与switch表一样多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.