簡體   English   中英

如果僅在運行時知道參數數目,如何調用函數指針

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM