2014-01-15 66 views
1

我試圖創建一個鏈接列表,將跟蹤我想要使用某些函數的順序。我有大約20個函數,都在我的代碼的幾個區域執行,但是它們的執行順序是動態的,所以我在創建一個列表,在其中插入哪個函數將在特定時間執行以清除將代碼放在只有一個區域用於所有if檢查,另一個區域用於執行這些功能。這使它看起來高效且易於使用。 問題我有當我想要傳遞變量。看看在C僞代碼...鏈接列表指向函數C

void func1() { ... } 
    void func2() { ... } 
    void func3(x,y) {...} 
    void func4(z) {...} 
    void func5() {...} 

    // Do some If checks to determine order 
    addFuncToList(func3); 
    addFuncToList(func5); 
    addFuncToList(func1); 

    while(condition) { 
     x++; 
     y--; 

     execute_funcs(currentNode); 
     currentNode = myList->next; 
    } 

    // Do some If checks to determine order 
    addFuncToList(func1); 
    addFuncToList(func5); 
    addFuncToList(func2); 

    while(condition2) { 
     execute_funcs(currentNode); 
     currentNode = myList->next; 
    } 

    void execute_funcs(currentNode) { 
     if(currentNode == 1) func1(); 
     if(currentNode == 2) func2(); 
     if(currentNode == 3) func3(); 
     ... 
    } 

所以我喜歡這種方法,但我不想做了一堆的全局變量的,我希望能在變量傳遞進入這些功能的大部分。大多數函數不需要傳入變量,但有些需要傳入不同的類型。任何想法?

+0

看起來您需要傳遞所有可能被調用的函數集中的一個函數需要的變量,然後忽略那些不需要的函數中的無用函數他們。 – CrazyCasta

+2

確保你確實需要在運行時確定函數的順序。我感覺這很容易成爲http://thedailywtf.com/Articles/Soft_Coding.aspx –

+0

的一種情況您可以使用數組來存儲函數參數,並將其傳遞給要調用的函數。這意味着這些函數必須是相同的類型,但鑄件可能是可能的。 –

回答

3

看起來您需要在列表中添加功能時創建的「上下文」概念。

因此,你的函數的原型變得看起來像這樣:

 
int func1(void* context); 
... 
int funcN(void* context); 

和列表應包含兩個函數的地址和它的上下文。在大多數情況下,上下文將是NULL,但是當一個函數需要時,它可以是一個結構,一個數據數組等等。只有呼叫者和特定功能知道該空白的確切含義*

1

這很可怕,但實際上只有兩種方式。您可以將每個可能的參數傳遞給每個函數,並讓每個函數僅使用它需要的參數。這是醜陋可怕的。

或者,您可以讓每個函數都有一個void *,並且可以根據需要進行強制轉換。 例如:

void func1(void*) { ... } 
void func2(void*) { ... } 
void func3(void* p) {x = **((int**)p); y = **((int**)(p+1)); ...} 
void func4(void* p) {z = *((int*)p); ...} 
void func5(void*) {...} 

//For the linked list, store a pointer to the function, and a pointer to the parameter. 
struct Node { 
    void (func*)(void*); 
    void* p; 
    Node* next; 
} Node; 

// Do some If checks to determine order 

//Use an array to store the two ints for func3. You could also use a struct. 
int* pForFunc3[2] = {&x, &y}; 
int z; 

//Func three gets passed an array with pointers to x and y, so it can use them. 
addFuncToList(func3 , &pForFunc3); 
addFuncToList(func5 , 0); 
addFuncToList(func1 , 0); 


while(condition) { 
    x++; 
    y--; 

    currentNode->func(currentNode->p); 
    currentNode = currentNode->next; 
} 

// Do some If checks to determine order 
addFuncToList(func1); 
addFuncToList(func5); 
addFuncToList(func2); 

while(condition2) { 
    currentNode->func(currentNode->p); 
    currentNode = currentNode->next; 
} 

這種方法涉及到很多可怕的無效*鑄造的,所以你需要確定自己在做什麼。但是,它比將每個參數傳遞給每個函數都更爲一般,並且避免了全局變量。

0

你只需要隱藏這個功能具有不同功能的事實。如果可以將函數指針與函數指針一起存儲,那麼exec函數將知道如何應用這些參數。在這裏,我假定所有的參數是相同的 - 如果這不是真的,那麼需要做更多的工作。這種方法的優點是你不必改變目標函數。

#include <stdlib.h> /* malloc, free */ 
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */ 

typedef struct { 
    int (*func)(); 
    int arity; 
    int params[0]; 
} node; 

node *construct(int (*func)(), int arity) { 
    node *n = malloc(sizeof(node) + sizeof(int) * arity); 
    n->func = func; 
    n->arity = arity; 
    return n; 
} 

void assign(node *n, ...) { 
    int i=0; 
    va_list va; 
    va_start(va,n); 
    for(; i<n->arity; i++) n->params[i] = va_arg(va,int); 
    va_end(va); 
} 

int exec(node *n) { 
    switch(n->arity) { 
    case 3: return n->func(n->params[0],n->params[1],n->params[2]); 
    case 2: return n->func(n->params[0],n->params[1]); 
    case 1: return n->func(n->params[0]); 
    default: return n->func(); 
    } 
} 

void destruct(node *n) { 
    free(n); 
} 

int sum(int a, int b, int c) { return a+b+c; } 
int add(int a, int b) { return a+b; } 
int ret(int i) { return i; } 
int one() { return 1; } 

int main() { 
    int result; 

    /* step 0: construct the nodes */ 

    node *n3 = construct(/* func = */ sum,/* params = */ 3); 
    node *n2 = construct(/* func = */ add,/* params = */ 2); 
    node *n1 = construct(/* func = */ ret,/* params = */ 1); 
    node *n0 = construct(/* func = */ one,/* params = */ 0); 

    /* step 1: assign the values */ 

    assign(n3,/* args */ 3,4,5); 
    assign(n2,/* args */ 3,4); 
    assign(n1,/* args */ 3); 

    /* step 2: execute the functions */ 

    result = exec(n3)+exec(n2)+exec(n1)+exec(n0); 

    /* step 3: destruct the nodes */ 

    destruct(n3); 
    destruct(n2); 
    destruct(n1); 
    destruct(n0); 

    return result; 
}