user-0 提问: 关于 回调函数 的理解与意义

回复:
user: user-0
content: 引用 15 楼 zhao4zhong1 的回复:理解和讨论之前请先学会如何观察！  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 赵老师   终于发话了

user: user-1
content: 理解和讨论之前请先学会如何观察！  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。

user: user-2
content: 你是不是认为只要传递函数指针，指针所指的函数就立即执行？ 或者对此有所疑问？ 不是这样的，调用不调用，看传入后的代码怎么使用这个指针 是储存但暂时不用，在需要的时候，还是立即使用，或者根本就不用 是仅仅调用一次，还是调用无数次。 看代码里怎么处理。  比较直接的。直接调用： 用函数指针名调用函数 假设函数指针名是f， 无参数，  f()  就是调用函数的代码; 比较复杂的储存起来，以备以后某个时候调用。 PS: 参数传递本身，不能完成对函数指针所指函数的调用。

user: user-2
content: 给你个代码吧  #include<cstdio> #include <vector> using namespace std; int a(){  printf("A"); return 0; } int b(){ printf("B");return 1;}  typedef int (*someCallBack)(); static vector<someCallBack> v; int add(someCallBack f){ v.push_back(f); return 0; } int  callit(){ int sum=0; for(int i=0;i<v.size();i++) sum+=v[i](); } return sum; }  void call(someCallBack f){  f();//立即调用 } int main(){ add(a); add(b); int s=callit(); printf("sum =%d\n"); call(a); call(b); return 0; }

user: user-3
content: 引用 11 楼 u013315260 的回复:[quote=引用 8 楼 user-3 的回复:] [quote=引用 6 楼 u013315260 的回复:] [quote=引用 4 楼 user-3 的回复:]  int a1(int s) //计算平方 { 	return s*s; } int a2(int s) //计算立方 { 	return s*s*s; } int b(int(*a)(int), int s) { 	return a(s); }  int main(int argc, char* argv[]) { 	printf("3的平方是：%d\n", b(a1, 3)); 	printf("3的立方是：%d\n", b(a2, 3)); 	return 0; }   版主 通过函数a 间接的调用 a1 a2 这样做的意义在哪了？   我直接在 main里 调用 a1(3);  a2(3) 不也一样吗？[/quote]  那是因为我现在b里没有实现其他功能，所以好像有没有b都一样，要是我b里还需要根据函数指针返回的结果作一些操作的话，你在main中只能调用b了吧 [/quote]  版主  能不能 给个具体的例子  理解一下    万分感谢[/quote]  上面不是给了：   int a1(int s) //计算平方 { 	return s*s; } int a2(int s) //计算立方 { 	return s*s*s; } int b(int(*a)(int), int s) { 	int ans = a(s); 	//这里还要执行一些操作 	//比如要将结果写到文件等 	return ans; }  int main(int argc, char* argv[]) { 	printf("3的平方是：%d\n", b(a1, 3)); 	printf("3的立方是：%d\n", b(a2, 3)); 	return 0; }

user: user-2
content: 回调函数，由他的调用者对应的系统的设计者，制定规则。 这个函数的返回值，参数的类型，以及函数的意义， 由调用者对应的系统设计者指定。 并在合适的时候，以适当的方式调用它。  回调函数的设计者，负责按照规则的要求，定制实现回调函数。 从而完成某种特定的任务。

user: user-0
content: 引用 8 楼 user-3 的回复:[quote=引用 6 楼 u013315260 的回复:] [quote=引用 4 楼 user-3 的回复:]  int a1(int s) //计算平方 { 	return s*s; } int a2(int s) //计算立方 { 	return s*s*s; } int b(int(*a)(int), int s) { 	return a(s); }  int main(int argc, char* argv[]) { 	printf("3的平方是：%d\n", b(a1, 3)); 	printf("3的立方是：%d\n", b(a2, 3)); 	return 0; }   版主 通过函数a 间接的调用 a1 a2 这样做的意义在哪了？   我直接在 main里 调用 a1(3);  a2(3) 不也一样吗？[/quote]  那是因为我现在b里没有实现其他功能，所以好像有没有b都一样，要是我b里还需要根据函数指针返回的结果作一些操作的话，你在main中只能调用b了吧 [/quote]  版主  能不能 给个具体的例子  理解一下    万分感谢

user: user-2
content: 整理一下  #include<cstdio> #include <vector> using namespace std; int a(){  printf("A"); return 0; } int b(){ printf("B");return 1;}  typedef int (*someCallBack)(); static vector<someCallBack> v; int add(someCallBack f){ v.push_back(f); ///注意，这里仅仅是储存这个函数指针，并没有调用函数。 return 0; } int  callit(){ int sum=0; for(int i=0;i<v.size();i++) sum+=v[i](); ///真正的函数调用代码在这里。这个函数并没有通过参数传递函数指针，                        ///它只是取出存储在v这个vector <someCallBack>全局变量，                       /// 中的函数指针，并调用对应的函数。 } return sum; }  void call(someCallBack f){  f();//立即调用 } int main(){ add(a);///没有调用 add(b);///没有调用 int s=callit();///调用保存下来的函数指针对应的函数，这里 a，b各被调用一次 printf("\tsum =%d\n",s); call(a);//立即调用函数 a call(b);//立即调用函数 b return 0; }   回调函数，传递函数指针后，函数何时调用，和 该callback 的实现机制有关  如果，你的意图是立即调用回调，那么你的代码中， 就必须出现直接间接调用 函数指针所指函数的代码 注意，函数指针传入后，形参函数指针， 就可以代表函数本身，用形参指针名， 就可以调用传入的指针参数,代表的那个函数。  如果你的意图是，保存下来，以后某个时间，或者状况下使用， 那么，你就可以设计为仅仅储存这个指针 并在适当时机，取出这个指针，用它来调用对应的函数。  回调函数，可以一次也不调用，也可仅仅调用一次 或者重复调用许多次， 不论如何调用 都是系统设计问题。  和参数传递关系不大， 参数传递，仅仅是把这个指针传到其他函数内部， 使得，使用该指针的代码，能够处理它。 怎么处理，和使用者的代码设计有关 而不是和 函数指针的传递有关， 函数指针的传递，并不能起到调用函数的作用。  但他能够起到桥梁作用， 使得这个指针对应的函数有机会被调用。

user: user-3
content: int a1(int s) //计算平方 { 	return s*s; } int a2(int s) //计算立方 { 	return s*s*s; } int b(int(*a)(int), int s) { 	return a(s); }  int main(int argc, char* argv[]) { 	printf("3的平方是：%d\n", b(a1, 3)); 	printf("3的立方是：%d\n", b(a2, 3)); 	return 0; }

user: user-3
content: 引用 6 楼 u013315260 的回复:[quote=引用 4 楼 user-3 的回复:]  int a1(int s) //计算平方 { 	return s*s; } int a2(int s) //计算立方 { 	return s*s*s; } int b(int(*a)(int), int s) { 	return a(s); }  int main(int argc, char* argv[]) { 	printf("3的平方是：%d\n", b(a1, 3)); 	printf("3的立方是：%d\n", b(a2, 3)); 	return 0; }   版主 通过函数a 间接的调用 a1 a2 这样做的意义在哪了？   我直接在 main里 调用 a1(3);  a2(3) 不也一样吗？[/quote]  那是因为我现在b里没有实现其他功能，所以好像有没有b都一样，要是我b里还需要根据函数指针返回的结果作一些操作的话，你在main中只能调用b了吧

user: user-0
content: 引用 5 楼 lm_whales 的回复:通常是会立即调用的 但也不是所有回调函数，都是这么做的 例如windows 窗口过程 只是系统把它存储起来，需要时候（有消息需要处理的时候）才会调用  Windows 应用程序，开始的时候，需要注册窗口过程  WNDCLASSEX wndclass; ...... wndclass.lpfnWndProc =WndProc; ...  RegisterClassEx(&wndclass); .......... 但是并不立即调用WndProc 只是消息循环中，才会调用 WndProc Windows 消息循环通常如下： MSG msg; while(GetMessage(&msg)){ TranslateMessage(&msg); DisptchMessage(&msg); ///具体来说，是这个API函数（系统调用）在调用 WndProc }  您可能有点误解 我的意思，我是说  a函数指针 作为参数 传递到 b的 形参的时候， b函数会调用 此指针指向的函数吗？ 也就是说b函数体 是空的，只有它的一个形参是a函数的指针。 所以b函数还是调用了 a函数？

user: user-0
content: 引用 4 楼 user-3 的回复: int a1(int s) //计算平方 { 	return s*s; } int a2(int s) //计算立方 { 	return s*s*s; } int b(int(*a)(int), int s) { 	return a(s); }  int main(int argc, char* argv[]) { 	printf("3的平方是：%d\n", b(a1, 3)); 	printf("3的立方是：%d\n", b(a2, 3)); 	return 0; }   版主 通过函数a 间接的调用 a1 a2 这样做的意义在哪了？   我直接在 main里 调用 a1(3);  a2(3) 不也一样吗？

user: user-0
content: 引用 2 楼 lm_whales 的回复:再例如，C标准库的qsort 如果不采用函数指针传递比较函数， C 就没有办法，实现这样一个通用的快速排序算法。 可是兄台  我都没明白 它的执行过程，函数指针 传递过去后， 是被调用函数 立即去调用 这个指针指向的 函数吗？ 然后回来再执行自己？

user: user-2
content: 通常是会立即调用的 但也不是所有回调函数，都是这么做的 例如windows 窗口过程 只是系统把它存储起来，需要时候（有消息需要处理的时候）才会调用  Windows 应用程序，开始的时候，需要注册窗口过程  WNDCLASSEX wndclass; ...... wndclass.lpfnWndProc =WndProc; ...  RegisterClassEx(&wndclass); .......... 但是并不立即调用WndProc 只是消息循环中，才会调用 WndProc Windows 消息循环通常如下： MSG msg; while(GetMessage(&msg)){ TranslateMessage(&msg); DisptchMessage(&msg); ///具体来说，是这个API函数（系统调用）在调用 WndProc }

user: user-2
content: 再例如，C标准库的qsort 如果不采用函数指针传递比较函数， C 就没有办法，实现这样一个通用的快速排序算法。

user: user-2
content: 有很大不同， 有很多时候，我们需要一个总的框架， 根据不同情况，调用不同函数， 例如求函数的定积分，可以写成通用函数， 调用不同函数，求出他们的积分。  如果不通过参数传递函数， 那么我们只好针对每个函数，写出一个对它求积分的函数。 这样积分算法，就不可以复用了