问题描述
函数指针的主要用途(从我收集到的)是将它们与一些变量一起传递给一个函数,然后该函数将调用指针指向的函数。为了获得类似的结果,可以传递任意整数而不是函数指针,并让 switch case 调用适当的函数;这也将绕过函数指针固有的限制,即您将指针传递给的函数需要确切地知道什么类型的函数即将到达它(它返回什么以及它期望什么变量。)
使用函数指针比上面提出的 switch case 方法有优势吗?我对可能缺少的函数指针的技术能力感兴趣,最好也有一些示例。
解决方法
如果每个函数都有不同的签名,您需要为每个函数设置一个单独的 case,以便调用正确的参数并获得正确的返回类型。
如果签名相同,您可以改为创建一个函数指针数组并只索引该数组。这避免了分支并且更易于维护。例如:
int add(int,int);
int sub(int,int);
typedef int (*math_func)(int,int);
math_func arr[] = { add,sub };
int call_math_func(int idx,int a,int b)
{
return math_func[idx](a,b);
}
,
我更喜欢尽可能使用函数指针,因为恕我直言它们使调用站点的意图更加明确,例如:
#include <stdio.h>
typedef void (*HelloWorld)(void);
void english(void) { printf("Hello,World!\n"); }
void italian(void) { printf("Ciao,Mondo!\n"); }
void greet_world_in(HelloWorld hello_world) { hello_world(); }
int main(void)
{
greet_world_in(english);
greet_world_in(italian);
return 0;
}
,
假设函数指针具有完全相同的原型,switch case 语句通常被实现为一个跳转表:
void conceptual_dispatcher_emulating_switch_case(int n) {
static const jmp_ptr_t jmp_table[5]={label_0,label_1,label_2,label_3,label_4};
if (n < 5) {
goto jmp_table[n];
}
return;
label_0 : return myfunc_1();
label_1 : return myfunc_2();
label_2 : return myfunc_3();
label_3 : return myfunc_4();
label_4 : return myfunc_5();
}
由此可以很容易地进行优化:
void conceptual_dispatcher_better(int n) {
static const function_ptr_t jmp_table[5]={myfunc_1,myfunc_2,myfunc_3,myfunc_4,myfunc_5};
if (n < 5) {
goto jmp_table[n];
}
return;
}
从这里开始,下一个合乎逻辑的步骤是
void conceptual_dispatcher_even_better(function_ptr_t *ptr) {
ptr();
}
从这里开始,下一步是使该内联或仅在没有调度程序的情况下调用 ptr。