现在的位置: 首页 > 综合 > 正文

囘調函數詳解

2013年09月21日 ⁄ 综合 ⁄ 共 2603字 ⁄ 字号 评论关闭

囘調函數進階一:瞭解囘調函數

調用函數:

如果參數是一個函數指針,調用者可以傳遞一個函數的地址給實現者,

即調用者提供一個函數但自己不去調用,而是讓實現者去調用它,這稱之為囘調函數。

囘調函數示例:

void func(void (*f)(void *),void *p);

實現過程:

調用者提供一個囘調函數,再提供一個準備傳遞給囘調函數的參數;

把囘調函數傳給參數f,把準備傳給囘調函數的參數按照void * 類型傳給參數p。

實現者呢,在適當的時候根據調用者傳來的函數指針f調用囘調函數,

將調用者傳來的參數p轉交給囘調函數,即調用f(p)。記住,此時f是一個函數指針,

真正的函數地址則是看調用者的傳遞了。

應用實例:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

typedef void (*callback_t)(void *);	
void my_func(callback_t,void *);

/*
 * 當然,正規的定義應該是這樣的:
 * void my_func(void (*callback_t)(void *),void *p);
 * 使用 typedef 會更清晰一些。
*/

void my_func(callback_t f,void *para)
{
	f(para);
}

static void say_hello(void *str)
{
	printf("%s\n",(const char *)str);
}

static void count_num(void *num)
{
	printf("%d\n",(int)num);
}

int main(int argc, char *argv[])
{
	my_func(say_hello,"Hello World!");
	my_func(count_num,2);
	return 0;
}

通俗的講,囘調函數實現了程序處理的自由性,靈活性。同樣的都是void *p 參數,

但是另一個函數,函數指針的地址(也就是囘調函數)不同,

因此可以通過對同一個參數傳遞不同的函數來處理不同的操作。

再比如下面這個示例:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

typedef int (*cmp_t)(const void *,const void *);
void *max(const void *base,size_t nmemb,size_t size,cmp_t cmp);

void *max(const void *base,size_t nmemb,size_t size,cmp_t cmp)
{
	size_t	i;
	const char *_base = base;
	const char *temp = _base;

	for(i=0;i<nmemb;i++){
		if(cmp(temp,_base+size*i)<0)
			temp = _base + size*i;
	}
	return (void *)temp;
}

typedef struct {
	const char *name;
	int	score;
}student_t;

static int cmp_student(const void *a,const void *b);
{
	if(((student_t *)a)->score > ((student_t *)b)->score)
		return 1;
	else if(((student_t)a)->score == ((student_t *)b)->score)
		return 0;
	else
		return -1;
}
int main(int argc,char **argv)
{
	student_t	list[4] = {{"Tom",68},{"Jerry",72},{"Moby",60},{"Kirby",89}};
	student_t	*pmax = max(list,sizeof(list)/sizeof(student_t),sizeof(student_t),cmp_student);
	printf("%s gets the highest score %d\n",pmax->name,pmax->score);
	exit(0);
}

囘調函數進階二:深入囘調函數

同步囘調:

在上面的例子中,囘調函數是被同步調用的。my_func()調用say_hello(),相當於調用者直接調用了自己提供的囘調函數。

比如,將main函數中的第一行替換成:sya_hello("Hello World!");也是完全可以的。

異步調用:

比起同步調用,異步調用也是很典型的。調用者首先將囘調函數傳給實現者,實現者記住這個函數,這稱為“註冊”一個囘調函數,然後當某個事件發生時實現者再調用先前註冊的函數。

比如信號處理函數sigaction(),首先註冊一個信號處理函數,當此信號發生的時候由操作系統調用該函數進行處理。

再比如創建線程函數pthread_create()註冊一個線程函數,當發生調度時操作系統切換到新註冊的線程函數中運行。

“從這個角度來看,凡是系統api參數中有函數指針,大多(or全部?)是這種囘調函數的形式”。

囘調函數進階三:提升囘調函數

總結:
簡單來說,在層次化程序設計中,一般都是上層函數調用下層函數,逐級調用。
而如果把函數的參數變為函數地址(也就是函數指針),那麼就可以實現函數的囘調,
也就是不必一直向下層調用。這樣,我們就稱之為囘調函數,這樣實現了層次化編程
中的函數自由、靈活的調用。
如果自己提供了一個囘調函數并實現了囘調函數,將之編譯成lib庫或是其他的形式。
那麼在應用中,一旦需要這個囘調函數,系統就會在lib庫中按照名字尋找。
1.可以實現動態綁定。通過運行時傳遞不同的函數地址,執行不同的操作。可以理解為多态。
2.可以實現消息通知和事件驅動。比如程序中設置一個計時器,到達指定時間則通知程序。
3.提供了一種代碼動態嵌入的方式,實現函數內部中斷的一種方式。比如程序出錯,程序需要額外處理,
可以嵌入一個囘調函數,啟動一個單獨線程去執行任務。而程序則繼續執行自己的後續代碼。
實際上,創建線程函數就是一個典型應用。

pthread_create(),其中有一個參數就是函數執行的地址,還有一個參數是參數。

ps:囘調函數都是全局函數、或者是靜態函數。想想這是爲什麽?

http://hi.baidu.com/gtfcugb/blog/item/57b836dd6e11f5e976c638f1.html

抱歉!评论已关闭.