了解開發語言的朋友應該都會對回調函數有所了解,在很多的程序開發語言中都能看到回調的身影。 很多場景下,當某個條件成立以后我們希望代碼執行某些指定的部分,這個時候可以考慮使用回調函數的方式,這樣做思路更加的清晰,也能使代碼結構的邏輯更加清晰,結構更加好。
那回調函數到底是什么呢? 它又是怎么實現的呢?
這是本次想要簡單分析的一個主題。
但是在說回調函數之前,我覺得很有必要先說明一下 “函數指針” 這個概念,它是回調函數能夠實現的重要基礎。
1、函數指針
學習過C語言的伙伴都知道,C語言中的靈魂 — 指針。 可以毫不猶豫地說,要檢驗你對C語言的掌握程度,那指針絕對是最好的考察方式。 指針的使用和變幻方式,真正的使用起來能讓你眼花繚亂。
下面是常見的指針的定義:
int *ptr1;
char *ptr2;
struct std *ptr3; // 結構體指針
那函數指針到底是什么呢?
函數指針:函數指針是指向函數的指針變量。 簡單理解是指向函數名的指針變量。
函數指針既然是指向函數的,那么它就可以像函數一樣,用于調用函數、傳遞參數等操作。 函數指針的定義方式如下:
函數返回值類型 (* 指針變量名) (函數參數列表);
“函數返回值類型”:表示該指針變量可以指向具有什么返回值類型的函數;
“函數參數列表”:表示該指針變量可以指向具有什么參數列表的函數。
舉例如下:
int (*func1)(void)
int (*func2)(int,char,...)
char (*func3)(int,char,...)
......
從上面的演示可以看到,函數指針的定義就是將一個函數中的 “函數名” 改成“(* 指針變量名)”的方式,從而實現了一個函數指針的定義。
但是這里需要注意的是:“(* 指針變量名)”兩端的括號是必須要有的,如果缺少了這對括號,那么這個定義的方式就會變為指針函數。 如下:
int *func1(void)
int *func2(int,char,...)
char *func3(int,char,...)
......
這種就不是函數指針了,而是指針函數。兩者差別是很大的。
特別需要需要注意的一點是:指向函數的指針變量沒有 ++ 和 -- 運算。
對于函數指針,一般為了方便使用,我們會選擇另外的一種定義方式:
typedef 函數返回值類型 (* 指針變量名) (函數參數列表);
比如:
typedef int (*Fun1)(int,...);
typedef int (*Fun2)(int, int,...);
typedef void (*Fun3)(void);
typedef void* (*Fun4)(void*);
......
2.、函數指針的使用方式
清楚了函數指針是什么東西了之后,那函數指針要怎么使用呢? 看下面的例子:
/* 1.首先定義一個函數 */
int Func(int x);
/* 2.然后定義一個函數指針 */
int (*p) (int x);
/* 3.將Func函數的首地址賦給指針變量p */
p = Func;
或
p = &Func;
/* 4.然后使用p調用Func函數 */
(*p) (int x);
因為函數名 Func 代表函數的首地址,所以經過賦值以后,指針變量 p 保存的就是Func的函數入口地址,即 p 就指向函數 Func() 代碼的首地址。
為了加深函數指針的使用方式,看下面的一段代碼你就明白了。 如下:
#include
int Max(int, int); //函數聲明
int main(void)
{
int a, b, c;
int(*p)(int, int); //定義一個函數指針
p = Max; //把函數Max賦給指針變量p, 使p指向Max函數
printf("please enter a and b:");
scanf("%d %d", &a, &b);
c = (*p)(a, b); //通過函數指針調用Max函數
printf("a = %d\\nb = %d\\nmax = %d\\n", a, b, c);
return 0;
}
int Max(int x, int y) //定義Max函數
{
int z;
if (x > y) z = x;
else z = y;
return z;
}
特別注意的是,因為函數名本身就可以表示該函數地址(指針),因此在獲取函數指針時,可以直接用函數名,也可以取函數的地址。
3. 函數指針可以作為函數的參數來使用
函數指針變量本身也是一個變量,也可以作為某個函數的參數進行使用的。 如下:
#include
#include
// 定義一個函數指針類型的 FunType
typedef void(*FunType)(int);
void myFun(int x);
void hisFun(int x);
void herFun(int x);
void callFun(FunType fp,int x);
int main()
{
callFun(myFun,1000);//傳入函數指針常量,作為回調函數
callFun(hisFun,5000);
callFun(herFun,4700);
return 0;
}
4、回調函數
前面講了函數指針,現在終于到了回調函數了。 到這部分,我們就不說太多的廢話,直接闡述回調函數是什么,回調函數要怎么使用,一步到位吧!
回調函數:如果一個函數的指針(函數名或地址)作為參數傳遞給另外一個函數,當這個指針被用來調用其所指向的函數時,就說這個指針所指向的函數是一個回調函數。
再簡明點說:回調函數不是直接調用該函數進行使用的,而是要通過另外的特定事件或者其他函數進行調用的,才能稱作回調函數。 定義一個函數然后直接調用,都不能稱為回調函數。
回調函數的定義方式和使用,直接通過下面的例子說明,相信大家一看就會明白。
例程1:
/* 回調函數 */
int Callback(void)
{
return 0;
}
int Library(int value,int (*MycallBackFunc)(void))
{
if(value == 1)
MycallBackFunc();
else
return 1;
}
int main()
{
Library(1,Callback); // 返回值為 0
return 0;
}
例程2:
int Callback_1(int a) // 回調函數1
{
printf("Hello, this is Callback_1: a = %d ", a);
return 0;
}
int Callback_2(int b) // 回調函數2
{
printf("Hello, this is Callback_2: b = %d ", b);
return 0;
}
int Callback_3(int c) // 回調函數3
{
printf("Hello, this is Callback_3: c = %d ", c);
return 0;
}
int MyHandle(int x, int (*MyCallback)(int))
{
MyCallback(x);
}
int main()
{
MyHandle(4, Callback_1);
MyHandle(5, Callback_2);
MyHandle(6, Callback_3);
return 0;
}
從上面的代碼可以看出,MyHandle() 函數的參數有一個指針,在 main() 函數里調用MyHandle() 函數的時候,給它傳入了函數 Callback_1()、Callback_2()、Callback_3() 的函數名,這時候的函數名就是對應函數的指針,也就是說,回調函數其實就是函數指針的一種用法。
到此,通過上面的函數指針的說明和回調函數的示例代碼,估計看到這里的朋友應該都明白了回調函數的使用了吧!
-
C語言
+關注
關注
180文章
7575瀏覽量
134214 -
指針
+關注
關注
1文章
475瀏覽量
70460 -
代碼
+關注
關注
30文章
4672瀏覽量
67780 -
回調函數
+關注
關注
0文章
87瀏覽量
11508 -
函數指針
+關注
關注
2文章
55瀏覽量
3760
發布評論請先 登錄
相關推薦
評論