我正在学习C中的回调函数,发现自己太难理解了 回调的概念。
我知道回调函数是用c中的函数指针实现的,意思是 我们可以通过使用指针来引用函数,就像我们使用指针一样 参考变量。
我在这里有两个函数实现:
1.第一个是使用回调函数
#include <stdio.h>
int add_two_number(int a, int b);
int call_func(int (*ptr_func)(int, int), int a, int b);
int main (int *argc, char *argv[])
{
printf("%d", call_func(add_two_number, 5, 9));
return 0;
}
int add_two_number(int a, int b)
{
return a + b;
}
int call_func(int (*ptr_func)(int, int), int a, int b)
{
return ptr_func(a, b);
}
2.第二个是使用普通函数调用:
#include <stdio.h>
int add_two_number(int a, int b);
int call_two_number(int a, int b);
int main (int *argc, char *argv[])
{
printf("%d", call_two_number(5, 9));
return 0;
}
int add_two_number(int a, int b)
{
return a + b;
}
int call_two_number(int a, int b)
{
return add_two_number(a, b);
}
这两个函数在两个数字和这两个数字之间进行简单的数学加法 功能也像我预期的那样正常工作。
我的问题是这两者有什么区别?当我们使用回调代替正常函数时?
答案 0 :(得分:3)
如果您不知道要在进行呼叫的地方呼叫什么功能,则会使用回叫。例如,如果你想减去两个数字该怎么办:
#include <stdio.h>
int add_two_number(int a, int b);
int sub_two_number(int a, int b);
int call_func(int (*ptr_func)(int, int), int a, int b);
int main (int *argc, char *argv[])
{
// Here is where we decide what the function should do for the first call
printf("%d", call_func(add_two_number, 5, 9));
// Here is where we decide what the function should do for the second call
printf("%d", call_func(sub_two_number, 5, 9));
return 0;
}
int add_two_number(int a, int b)
{
return a + b;
}
int sub_two_number(int a, int b)
{
return a - b;
}
int call_func(int (*ptr_func)(int, int), int a, int b)
{
return ptr_func(a, b); // Here is the place the call is made
}
回调对于解耦代码也很有用。考虑具有多个按钮的应用程序。如果没有回调,您必须在按钮代码中有一些逻辑来确定单击每个按钮时会发生什么。通过使用回调,按钮代码可以保持通用,但每个按钮仍然可以在单击时调用不同的操作。
答案 1 :(得分:1)
回调函数的一种用法是Inversion of Control。 假设你没有一个你调用它的函数的库,但是一个框架可以完成大部分工作而你只需添加函数来填充“填充漏洞”。 您将回调函数传递给框架,以便它知道在哪里回调:)
回调函数可以在以后交换,你可以从框架功能和你自己的。(/ p>)中获得很好的抽象
答案 2 :(得分:1)
回调为您提供了一个抽象层,允许您取消调用函数的行为,而不必知道需要调用它的函数的名称。例如他们让你写“通用”功能
function do_something(pointer foo) {
}
假设这个“do_something”函数在您的问题中称为LOT,它需要“回调”到您的程序以获取更多数据。
do_something(&callback_func_number_1);
do_something(&callback_func_number_2);
等。
一个单一的功能,无论做什么,都使用回调来请求它需要的任何东西。
相比之下,通过直接调用,您需要一个特定的do_something
用于您拥有的每个变体:
do_something_and_call_data_from_func1() { ... }
do_something_and_call_data_from_func2() { ... }
答案 3 :(得分:0)
我的问题是这两者有什么区别?
前者比后者更模块化,即: 让我们说你想要实现一个简单的计算器。第一个解决方案可以轻松编写多个运算符&#34;您将传递给call_func,具体取决于您需要的那个。
示例强>:
#include <stdio.h>
int add_two_number(int a, int b);
int sub_two_number(int a, int b);
int call_func(int (*ptr_func)(int, int), int a, int b);
int main (int *argc, char *argv[])
{
if (argv[1][0] == '+')
printf("%d\n", call_func(add_two_number, 5, 9));
else if (argv[1][1] == '-')
printf("%d\n", call_func(sub_two_number, 5, 9));
return 0;
}
int add_two_number(int a, int b)
{
return a + b;
}
int sub_two_number(int a, int b)
{
return a - b;
}
int call_func(int (*ptr_func)(int, int), int a, int b)
{
return ptr_func(a, b);
}
在这种特殊情况下,使用函数指针而不是普通函数调用并没有多大好处,但通常它可以帮助你编写更清晰的代码(而不是多个if)。
当我们使用回调代替普通函数时?
在大多数情况下,当您需要模块化时,您将使用它们。如果你发现自己编写了4个具有相同循环或/和条件的函数,只有一个函数不同,你应该使用函数指针。 它们还与qsort函数一起使用,以定义您自己的排序规则。在处理外部库时也可以找到函数指针,例如GLFW在按键时使用它们(除其他外)定义自己的函数:请参阅example。
答案 4 :(得分:0)
当在编译时不知道要调用的函数时,使用回调函数。一个例子是在一些库中完成的通用审计例程,但实际的清理例程是程序中的一个函数。
回调函数(或函数指针,在下一个示例的情况下)的另一个用途是具有函数指针数组或包含函数指针的结构数组。只需在调用需要发生时将索引更改为数组,就可以调用不同的函数。一个例子是设备驱动程序。内核接口对大多数设备和大多数相同的函数调用使用相同的结构。使用函数指针,文件上的打开调用通过vnode系统路由,而设备上的打开调用则通过设备驱动程序进行路由。这允许一种简单的方法来映射函数调用,而无需使用switch语句或大型if-then-else链。它还允许在运行时添加和删除函数调用,因为内核模块被加载和卸载(在设备驱动程序的情况下)。
答案 5 :(得分:0)
许多答案源于常见的实施。我将尝试给出回调首次出现的观点。
这两者有什么区别?
只是某种程度的间接。
当我们使用回调代替正常功能时?
当事件驱动系统(如Windows中的小部件)变得流行时,出现了回调。您将获得一个事件(触发器),并且回调(对函数的引用)将嵌入到事件中断代码中,或者
对于早期系统,一些其他代码块将决定调用哪个函数。在任何一种情况下,术语“回调”都是被创造出来表明这是回应事件的回调函数。
如果它们是指针,回调很有用,因为您可以方便地将它们更改为(到另一组功能),但您不必以这种方式使用它们。如果你的主程序是某种响应某个事件的开关,那么你可以将你的任何一个版本称为&#39; callback&#39;功能