Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 与充满函数调用的开关相比,函数指针有什么优势?_C - Fatal编程技术网

C 与充满函数调用的开关相比,函数指针有什么优势?

C 与充满函数调用的开关相比,函数指针有什么优势?,c,C,函数指针的主要用途(从我收集的资料中)是将它们连同一些变量一起传递给一个函数,然后该函数将调用指针指向的函数。为了获得类似的结果,可以传递一个任意整数而不是函数指针,并让开关盒调用相应的函数;这也将绕过函数指针固有的限制,即您要将指针传递到的函数需要确切地知道它将得到什么类型的函数(它返回什么以及它期望什么变量) 使用函数指针比上面提出的switch-case方法有优势吗?我对我可能缺少的函数指针的技术功能感兴趣,最好还有一些示例。如果每个函数都有不同的签名,那么为了调用正确的参数并获得正确的返

函数指针的主要用途(从我收集的资料中)是将它们连同一些变量一起传递给一个函数,然后该函数将调用指针指向的函数。为了获得类似的结果,可以传递一个任意整数而不是函数指针,并让开关盒调用相应的函数;这也将绕过函数指针固有的限制,即您要将指针传递到的函数需要确切地知道它将得到什么类型的函数(它返回什么以及它期望什么变量)


使用函数指针比上面提出的switch-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);
}

我更喜欢在可能的情况下使用函数指针,因为imho它们使调用站点的意图更加明确,例如:

#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;
}
#包括
typedef void(*HelloWorld)(void);
void英语(void){printf(“你好,世界!\n”);}
无效意大利语(无效){printf(“再见,蒙多!\n”);}
在(HelloWorld hello_world){hello_world()}
内部主(空)
{
用英语问候世界;
用意大利语问候世界;
返回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();
}

从这里开始,下一步是内联或在没有调度程序的情况下直接调用ptr。

您的意思是除了使用
switch
语句造成维护噩梦之外?调用任何函数都需要遵守函数的约定;函数指针在这方面没有什么不同。传统上,函数指针表比开关更快。现在这不重要了。事实上,函数指针可能会减慢速度,因为它们会阻止内联<代码>按国家分类(…)<代码>qsort(…,按高度)。。。C库编写人员不知道您会选择什么函数,他们根本不可能使用
开关来实现这一点。传统上,函数指针表(或标签表)是编译器实现(快速)开关的机制。
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();
}