为什么使用回调而不是正常的函数调用?

时间:2013-05-12 10:20:42

标签: c callback function-pointers

我正在努力理解回调,并且确实得到了这个想法,但不明白为什么它真的需要。

具体来说,它通过正常的函数调用提供了哪些额外的好处?我在这里看到接受的答案:What is a "callback" in C and how are they implemented?

我在下面重做同样的事情,只是没有使用函数指针。这有什么不同?

void populate_array(int *array, size_t arraySize)
{
   for (size_t i=0; i<arraySize; i++)
      array[i] = getNextRandomValue();
}

int getNextRandomValue(void)
{
   return rand();
}

int main(void)
{
   int myarray[10];
   populate_array(myarray, 10);
   ...
}

如果低层软件需要调用在更高层定义的函数,这是否有用?

4 个答案:

答案 0 :(得分:7)

这个实现的不同之处在于,它知道填充数组的唯一方法是硬编码:getNextRandomValue 它填充数组的方式,它是提供populate_array功能的库的一部分。从本质上讲,这两个函数被组合成一个整体(说同样的事情的奇特方式是说它们“紧密耦合”)。

使用原始实现,我可以执行以下所有操作,而无需更改populate_array中的一行:

int getNextRandomValue(void) {
    return rand();
}
int getNextEvenValue(void) {
    static int even = 2;
    return (even += 2);
}
int getNextNegativeValue(void) {
    static int neg = -1;
    return neg--;
}
int getNextValueFromUser(void) {
    int val;
    scanf("%d", &val);
    return val;
}

populate_array(myarray, 10, getNextRandomValue);
populate_array(myarray, 10, getNextEvenValue);
populate_array(myarray, 10, getNextNegativeValue);
populate_array(myarray, 10, getNextValueFromUser);

通过实施,我必须为每个案例编写一个单独的populate_array。如果填充我需要的数组的方式不是库的一部分,我就可以实现整个populate_array,而不仅仅是它的产生值的生成器函数。在这种情况下,这可能不是那么糟糕,但是在回调真正发光(线程,异步通信)的情况下重新实现原始而没有回调将是令人望而却步的。

答案 1 :(得分:2)

在您的示例中,必须在编译时知道getNextRandomValue。这意味着您不能将该函数重用于getNextRandomValue的不同定义,也不能让其他用户链接到您的代码并指定其getNextRandomValue版本。请注意,这不是回调,而是“通用”函数:将getNextRandomValue视为函数的占位符。

回调是“通用”函数的一种特殊用法:在完成异步任务时调用它们,以通知用户操作结果(或进度)。

我不认为函数指针只适合低到高级别的通信。如上所述,函数指针允许您在C中构建通用代码。快速示例qsort():订单排序需要一个函数,给定ab,告诉{{1} }},a>ba<b,以便a==ba可以按正确的顺序排列。好吧,b允许您为订单提供您自己的定义,从而提供一般的,可重复使用的代码。

答案 2 :(得分:0)

要在此处优化其他答案:您的函数populate_array名称不正确。它应该命名为populate_array_with_random_values

答案 3 :(得分:0)

正如你在答案中所说,“c中没有回调”。只有一种方法可以将函数指针传递给函数。

这通常不仅适用于需要在更高级别调用函数的低层软件,尽管这通常可能是如何使用它。

将函数指针作为参数传递是编写代码的一种优雅方式。在您的示例中,如果您想要获得下一个随机值的两个变体,您已经看到如何更容易将函数作为参数传递,而不是尝试传递一个参数,然后选择下一个函数来调用开关。