我正在努力理解回调,并且确实得到了这个想法,但不明白为什么它真的需要。
具体来说,它通过正常的函数调用提供了哪些额外的好处?我在这里看到接受的答案: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);
...
}
如果低层软件需要调用在更高层定义的函数,这是否有用?
答案 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()
:订单排序需要一个函数,给定a
和b
,告诉{{1} }},a>b
或a<b
,以便a==b
和a
可以按正确的顺序排列。好吧,b
允许您为订单提供您自己的定义,从而提供一般的,可重复使用的代码。
答案 2 :(得分:0)
要在此处优化其他答案:您的函数populate_array
名称不正确。它应该命名为populate_array_with_random_values
。
答案 3 :(得分:0)
正如你在答案中所说,“c中没有回调”。只有一种方法可以将函数指针传递给函数。
这通常不仅适用于需要在更高级别调用函数的低层软件,尽管这通常可能是如何使用它。
将函数指针作为参数传递是编写代码的一种优雅方式。在您的示例中,如果您想要获得下一个随机值的两个变体,您已经看到如何更容易将函数作为参数传递,而不是尝试传递一个参数,然后选择下一个函数来调用开关。