回调函数与C

时间:2015-05-22 18:37:11

标签: c function callback

我正在学习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);
}

这两个函数在两个数字和这两个数字之间进行简单的数学加法 功能也像我预期的那样正常工作。

我的问题是这两者有什么区别?当我们使用回调代替正常函数时?

6 个答案:

答案 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;功能