如果仅在运行时知道参数的数量,我如何调用函数指针

时间:2014-09-29 01:47:16

标签: c arrays function-pointers

在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语句中为每个我想支持的参数提供一个案例。 所以我的问题是:是否有一种更简单的方法可以做到这一点并不是那么丑陋并且可以使用任意数量的参数?

2 个答案:

答案 0 :(得分:3)

如果可能的话,不是为每个参数提供单独的函数,而是编写一个函数,该函数采用int s的数组而不是计数,或者甚至考虑使用<stdarg.h>,但是你可以使用{{1}}仍然需要某种哨兵或计数。

否则,您将进入语言标准本身无法保证的非便携式实现指定行为....

使用一些调用约定(例如read here for x86 examples),您可以使用额外的参数调用该函数,并且当正确使用感兴趣的函数时,它们会在寄存器或堆栈中被忽略,然后被丢弃为恢复原始堆栈指针。在其他体系结构中,函数返回时调整堆栈指针的数量与函数参数的数量有关,因此上述方法将崩溃。如果您想要阅读编译器/系统& #39;惯例并且有一个非便携式解决方案,这是一个选项。

否则,再次根据您的调用约定,您可以在调用函数之前使用汇编语言在堆栈上推送一些参数。我已经看到了代码在stackoverflow上执行此操作的问题,但可能需要一些挖掘来找到一个。不过,您仍然想要一个与您正在使用的呼叫约定相对应的。

答案 1 :(得分:2)

这可以稍微改善一下:

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,但这与切换表一样多。