6

我试图理解回调,并明白这个想法,但不明白为什么真的需要它。

具体来说,与普通函数调用相比,它提供了哪些额外的好处?我在这里查看接受的答案:什么是 C 中的“回调”以及它们是如何实现的?

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

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

4 回答 4

8

这个实现的不同之处在于它知道填充数组的唯一方法是硬编码的: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,而不仅仅是它的产生值的生成器函数。在这种情况下,这可能不是那么糟糕,但在回调真正发挥作用(线程、异步通信)的情况下,重新实现没有回调的原始版本将是令人望而却步的。

于 2013-05-12T10:29:34.217 回答
2

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

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

我不认为函数指针只适合从低到高级的通信。如上所述,函数指针允许您在 C 中构建通用代码。一个简单的示例qsort():顺序排序需要一个函数,给定aand b,告诉是否a>b,a<ba==b, 以便aandb可以按正确的顺序放置。好吧,qsort让您为订单提供自己的定义,从而提供一段通用的、可重用的代码。

于 2013-05-12T10:29:46.890 回答
0

在此处完善其他答案:您的函数populate_array名称不好。它应该被命名为populate_array_with_random_values.

于 2013-05-12T10:30:23.930 回答
0

正如您链接到“c 中没有回调”的答案中所说。只有一种方法可以将函数指针传递给函数。

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

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

于 2013-05-12T10:38:36.810 回答