callback用法簡介

源地址:https://argcv.com/articles/2669.cgit

 

callback,函數的回調,從ANSI C開始,一直被廣爲使用。不管是windows API的所謂消息機制,動態連接庫的調用,仍是sqlite的命令,gcc下的pthread,qsort。callback都在其中起着難以替代的做用。

那麼,callback爲什麼如此受到親睞呢?由於它能夠以一個函數爲參數,放到參數列表交給API,讓API調用。好比有個文件夾下有一千萬個文件,咱們但願對每一個文件進行一些處理,好比查看文件長度是否超過512字節。而遍歷這個文件夾的程序是個API。若是不使用callback,API可能有兩種辦法,一種是申請一個超巨大的空間,而後把找到的全部文件名都放進去,而後返回這個空間(相似的還有把這組文件名寫到文件中,一個意思),這樣速度的確很快,並且簡單方便,但問題是,一千萬個文件,佔用的空間是如此的龐大,空間複雜度爲O(n),而咱們只是要對每一個文件進行一點小小的處理而已,實在是殺雞焉用宰牛刀。另外一個方法是搞個迭代器,每次只返回一個文件名,下次調用再返回下個。爲了線程安全,每次傳參都得來個指針之類的記錄本身的進度。若是作的細心,也能夠作的很快,也不佔用空間。但問題是,只是個簡單的遍歷文件夾的API,這麼折騰好累哦。而若是使用callback,事情就簡單不少了。主程序調用API,把處理文件的函數用參數的方法傳遞給API,API每找到一個文件名,就調用這個函數,當場處理不用存儲任何文件名。這樣空間複雜度是O(1),並且方便有效,何樂而不爲呢?
github

callback具體怎麼實現的呢?我在本文中作一個小小的demo。
Demo的實現的功能是這樣的:
bar.c調用foo.c的一個函數,請求給一個magic number。但foo.c的函數並非直接返回,而是調用bar.c傳遞過來的函數use_magic_num,把magic number 做爲參數使用進去。sql

首先,定義最後要被調用的函數use_magic_num以下:windows

1
2
3
4
5
6
void use_magic_num( int magic_num);
 
void use_magic_num( int magic_num)
{
     printf ( "bar.c : magic number is %d \n" , magic_num);
}

也就是傳進去一個參數,而後函數會打印出這個magic number。它被放置在bar.c下安全

而後foo.h中定義API get_magic_num的原型函數

1
void get_magic_num( void (*callback)( int magic));

它的參數列表和普通的有點區別,傳入的是一個函數指針,這個函數必須是原型爲有一個int類型爲參數,返回爲void。其餘的就和普通的函數同樣了。spa

對get_magic_num進行實現。線程

1
2
3
4
5
6
7
typedef void (*foo_run_magic)( int );
 
void get_magic_num(foo_run_magic foo)
{
     int magic = 9;
     foo(magic);
}

我麼能夠看到,在這兒,我作了點小花招,我typedef了這個函數指針,這樣咱們能夠直接使用foo_run_magic來代替麻煩的各類括號的函數指針了。
而後調用 foo,其實就是調用傳入的參數。在本工程中,也就是前面寫的use_magic_num了。
雖然foo.c徹底看不見use_magic_num,但徹底不妨礙函數的使用。指針

最後定義bar.c的主程序code

1
2
3
4
5
int main( int argc, char *argv[])
{
     get_magic_num(use_magic_num);
     return 0;
}

也就是調用foo並傳入use_magic_num的函數了。

編譯和執行結果大體是以下的樣子:

1
2
3
4
5
6
7
[yu@argcv callback]$ make
gcc -c -Wall -std=c99 bar.c -o bar.o
gcc -c -Wall -std=c99 foo.c -o foo.o
gcc -Wall -std=c99 -o bar bar.o foo.o
[yu@argcv callback]$ ./bar
bar.c : magic number is 9
[yu@argcv callback]$

完整的工程請參考此處

相關文章
相關標籤/搜索