我正在尝试创建一个链接列表,该列表将跟踪我想要使用某些功能的顺序。我有大约20个函数都在我的代码的几个区域中执行,但它们执行的顺序是动态的,所以我正在创建一个列表,我插入哪个函数将在特定时间执行以清理代码只有一个区域用于所有if检查,另一个区域用于执行这些功能。这使它看起来高效且易于使用。 我遇到的问题是我想传递变量。看看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 :(得分:3)
看起来你需要" context"的概念。在向列表中添加函数时创建。
因此你的函数原型看起来像这样:
int func1(void* context); ... int funcN(void* context);
,列表应包含函数地址及其上下文。在大多数情况下,上下文将为NULL,但是当函数需要时,它可以是结构,数据数组等等。只有调用者和特定函数才知道该void *
的确切含义答案 1 :(得分: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;
}
这种方法涉及很多可怕的void * cast,所以你需要确定你在做什么。但是,它比将每个参数传递给每个函数更通用,它避免了全局变量。
答案 2 :(得分:0)
你只需要隐藏函数具有不同arity的事实。如果您可以将arity与函数指针一起存储,那么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;
}