?? 什么是回調函數那_編程論壇.htm
字號:
style="FONT-WEIGHT: bold; COLOR: red">5</FONT> 樓</A> </DIV> <A
href="mailto:zy-841120@163.com"><IMG alt=點擊這里發送電子郵件給luckbird
src="什么是回調函數那_編程論壇.files/email.gif" align=middle border=0></A> </DIV>
<DIV
style="TEXT-INDENT: 0px; LINE-HEIGHT: 22px; PADDING-TOP: 5px; HEIGHT: 22px"><B></B></DIV>
<DIV
style="PADDING-RIGHT: 0px; MARGIN-TOP: 10px; FONT-SIZE: 9pt; OVERFLOW-X: hidden; WIDTH: 97%; WORD-BREAK: break-all; LINE-HEIGHT: normal; HEIGHT: 160px; WORD-WRAP: break-word">還是不太理解 呼喚達人給詳細點的解釋</DIV></DIV></DIV>
<DIV class=postbottom1>
<DIV class=postuserinfo style="HEIGHT: 24px">
<DIV style="FLOAT: left"><IMG style="MARGIN: 4px"
src="什么是回調函數那_編程論壇.files/ip.gif"></DIV>2006-3-25 19:38:00</DIV>
<DIV class=postie
style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; TEXT-INDENT: 10px; PADDING-TOP: 0px; HEIGHT: 24px">
<DIV style="FLOAT: right; MARGIN-RIGHT: 5px"><A
href="http://bbs.bc-cn.net/dispbbs.asp?boardID=55&ID=52123#top"><IMG
style="BORDER-TOP-WIDTH: 0px; MARGIN-TOP: 3px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px"
alt="" src="什么是回調函數那_編程論壇.files/p_up.gif"></A> </DIV>
<DIV></DIV></DIV></DIV><A name=77349></A><A id=l6 name=6></A>
<DIV class=postlary2>
<DIV class=postuserinfo>
<DIV
style="FILTER: glow(color='#A6BA98',strength='2'); FLOAT: left; MARGIN: 13px 0px 0px 2px; WIDTH: 123px; LINE-HEIGHT: 23px; HEIGHT: 27px"><FONT
color=#000066><B>幽園香客</B></FONT></DIV>
<DIV
style="FLOAT: left; MARGIN: 13px 0px 0px; WIDTH: 23px; TEXT-INDENT: 0px; LINE-HEIGHT: 23px; HEIGHT: 27px"><IMG
alt=帥哥喲,離線,有人找我嗎? src="什么是回調函數那_編程論壇.files/ofMale.gif"> </DIV>
<DIV style="MARGIN: 0px 0px 0px 24px"><IMG height=90
src="什么是回調函數那_編程論壇.files/image2.gif" width=82><BR><IMG
style="MARGIN: 1px 0px 2px"
src="什么是回調函數那_編程論壇.files/level1.gif"><BR>來自:NUA<BR>等級:論壇游民<BR>文章:173<BR>積分:2761<BR>注冊:2006年2月27日<BR></DIV></DIV>
<DIV class=postie>
<DIV class=dispbbs_hr>
<DIV style="FLOAT: right"><A title=下一樓 onclick=xl(7)
href="http://bbs.bc-cn.net/dispbbs.asp?boardID=55&ID=52123#7">第 <FONT
style="FONT-WEIGHT: bold; COLOR: red">6</FONT> 樓</A> </DIV> <A
href="mailto:youyuanxiangke@yahoo.com"><IMG alt=點擊這里發送電子郵件給幽園香客
src="什么是回調函數那_編程論壇.files/email.gif" align=middle border=0></A> </DIV>
<DIV
style="TEXT-INDENT: 0px; LINE-HEIGHT: 22px; PADDING-TOP: 5px; HEIGHT: 22px"><B></B></DIV>
<DIV
style="PADDING-RIGHT: 0px; MARGIN-TOP: 10px; FONT-SIZE: 9pt; OVERFLOW-X: hidden; WIDTH: 97%; WORD-BREAK: break-all; LINE-HEIGHT: normal; HEIGHT: 160px; WORD-WRAP: break-word">轉貼:<BR><BR>
<P>先泛后精,先淺后深”的道理可是知易行難,所以常常會給技術上的小細節糾纏著,搞得暈暈乎,其中“回調函數”就是其中之一了,雖然回用,但是老是不明白其中的含義,眾多的書本也說得隱晦不清。直到不久前看到一篇文章才總算比較清晰了解。</P><BR>
<P>概括起來,回調機制包括兩部分:服務執行者和服務方式制定者。<BR>1.
服務執行者先制定服務規范;<BR>2.服務方式制定者然后按照規范制定服務方式;<BR>3.然后執行者按照這個方式提供服務。<BR>回調函數的方式是把函數指針的作為參數傳遞進去,所以規范就是約定函數的參數類型,個數。</P><BR>
<P>這篇文章如下:<BR> 調用(calling)機制從匯編時代起已經大量使用:準備一段現成的代碼,調用者可以隨時跳轉至此段代碼的起始地址,執行完后再返回跳轉時的后續地址。
CPU為此準備了現成的調用指令,調用時可以壓棧保護現場,調用結束后從堆棧中彈出現場地址,以便自動返回。借堆棧保護現場真是一項絕妙的發明,它使調用<BR>者和被調者可以互不相識,于是才有了后來的函數和構件,使吾輩編程者如此輕松愉快。若評選對人類影響最大之發明,在火與車輪之后,筆者當推壓棧調用。<BR>
話雖這樣說,此調用機制并非完美。回調函數就是一例。函數之類本是為調用者準備的美餐,其烹制者應對食客了如指掌,但實情并非如此。例如,寫一個快速排序<BR>函數供他人調用,其中必包含比較大小。麻煩來了:此時并不知要比較的是何類數據--整<BR>數、浮點數、字符串?于是只好為每類數據制作一個不同的排序函數。更<BR>通行的辦法是在函數參數中列一個回調函數地址,并通知調用者:君需自己準備一個比較函數,其中包含兩個指針類參數,函數要比較此二指針所指數據之大小,并<BR>由函數返回值說明比較結果。排序函數借此調用者提供的函數來比較大小,借指針傳遞參數,可以全然不管所比較的數據類型。被調用者回頭調用調用者的函數(夠<BR>咬嘴的),故稱其為回調(callback)。<BR> 回調函數使程序結構亂了許多。Windows
API
函數集中有不少回調函數,盡管有詳盡說明,仍使初學者一頭霧水。恐怕這也是無奈之舉。無論何種事物,能以樹形結構單向描述畢竟讓人舒服些。如果某家族中孫<BR>輩又是某祖輩的祖輩,恐怕無人能理清其中的頭緒。但數據處理之復雜往往需要構成網狀結構,非簡單的客戶/服務器關系能窮盡。<BR>
Windows 系統還包含著另一種更為廣泛的回調機制,即消息機制。消息本是 Windows
的基本控制手段,乍看與函數調用無關,其實是一種變相的函數調用。發送消息的目的是通知收方運行一段預先準備好的代碼,相當于調用一個函數。消息所附帶的 WParam
和 LParam 相當于函數的參數,只不過比普通參數更通用一些。應用程序可以主動發送消息,更多情況下是坐等 Windows
發送消息。一旦消息進入所屬消息隊列,便檢感興趣的那些,跳轉去執行相應的消息處理代碼。操作系統本是為應用程序服務,由應用程序來調用。而應用程序一旦<BR>啟動,卻要反過來等待操作系統的調用。這分明也是一種回調,或者說是一種廣義回調。其實,應用程序之間也可以形成這種回調。假如進程<BR>B
收到進程 A 發來的消息,啟動了一段代碼,其中又向進程
A<BR>發送消息,這就形成了回調。這種回調比較隱蔽,弄不好會搞成遞歸調用,若缺少終止條件,將會循環不已,直至把程序搞垮。若是故意編寫成此遞歸調用,并設好<BR>終止條件,倒是很有意思。但這種程序結構太隱蔽,除非十分必要,還是不用為好。<BR>
利用消息也可以構成狹義回調。上面所舉排序函數一例,可以把回調函數地址換成窗口handle。如此,當需要比較數據大小時,不是去調用回調函數,而是借 API 函數
SendMessage
向<BR>指定窗口發送消息。收到消息方負責比較數據大小,把比較結果通過消息本身的返回值傳給消息發送方。所實現的功能與回調函數并無不同。當然,此例中改為消<BR>息純屬畫蛇添腳,反倒把程序搞得很慢。但其他情況下并非總是如此,特別是需要異步調用時,發送消息是一種不錯的選擇。假如回調函數中包含文件處理之類的低<BR>速處理,調用方等不得,需要把同步調用改為異步調用,去啟動一個單獨的線程,然后馬上執行后續代碼,其余的事讓線程慢慢去做。一個替代辦法是借
API 函數
PostMessage發送一個異步消息,然后立即執行后續代碼。這要比自己搞個線程省事許多,而且更安全。<BR>
如今我們是活在一個 object 時代。只要與編程有關,無論何事都離不開 object。但 object
并未消除回調,反而把它發揚光大,弄得到處都是,只不過大都以事件(event)的身份出現,鑲嵌在某個結構之中,顯得更正統,更容易被人接受。應用程序
要使用某個構件,總要先弄清構件的屬性、方法和事件,然后給構件屬性賦值,在適當的時候調用適當的構件方法,還要給事件編寫處理例程,以備構件代碼來調<BR>用。何謂事件?它不過是一個指向事件例程的地址,與回調函數地址沒什么區別。<BR> 不過,此種回調方式比傳統回調函數要高明許多。首先,它把讓人不太舒服的回調函數變成一種自然而然的處理例程,使編程者頓覺氣順。再者,地址是一個危險的<BR>東西,用好了可使程序加速,用不好處處是陷阱,程序隨時都會崩潰。現代編程方式總是想法把地址隱藏起來(隱藏比較徹底的如
VB 和
Java),其代價是降低了程序效率。事件例程使編程者無需直接操作地址,但并不會使程序減速。更妙的是,此一改變,本是有損程序結構之奇技怪巧變成一種<BR>嶄新設計理念,不僅免去被人抨擊,而且逼得吾等凡人凈手更衣,細細研讀,仰慕至今。只是偶然靜心思慮,發覺不過一瓶舊酒而已,故引得此番議論,讓<ST1:PERSONNAME
w:st="on" productid="諸">諸</ST1:PERSONNAME>君見笑 了。
事件驅動程序設計是圍繞著消息基礎形成的,發生一個事件,伴隨著一大堆的消息。<BR>
我理解“回調機制”是window 在執行某個API函數的過程中,調用指定的一個函數。我們可以模擬一下:<BR>假設 ms
提供一個函數叫做 EnumFont
,該函數是得到所有的字體,假設它的實現是<BR>EnumFont()<BR>{<BR> while ( (f
=FindNextFont())
!=NULL)<BR> {<BR>
printf("fontname: " +
f.name);<BR> }<BR>}<BR>這樣就循環顯示出所有的字體名稱。但是,開發者可能對字體信息另有用處,那么如何才能讓開發者能使用這些信息呢,于是做改進:<BR>EnumFont(
void* userFunc )<BR>{<BR> while ( (f =FindNextFont())
!=NULL)<BR> {<BR>
printf("fontname: " + f.name);<BR> if (
userFunc!=NULL) userFunc( f) ;<BR> }<BR>}<BR>假設userFunc
是一個函數 void f(<BR>FontObject font).這樣使用者只需要定義一個函數:<BR> void myfunc(
FontObject
font)<BR>
{<BR> <BR>listCtrl.Addstring
(
font.name);<BR>
<BR>}<BR>通過使用 EnumFont ( myfunc) 就可以將所有額字體信息添加到一個列表框中。那么我們稱
myfunc是一個回調函數,即讓某個系統函數調用的函數。因此可以得出結論:<BR>1 回調函數是由開發者按照一定的原型進行定義的函數<BR>2
回調函數并不由發者直接調用執行<BR>3 回調函數通常作為參數傳遞給系統API,由該API來調用。<BR>4
回調函數可能被系統API調用一次,也可能被循環調用多次。<BR>比如 函數int
EnumFontFamilies(<BR> HDC<BR>hdc,
//<BR>handle to device control<BR> LPCTSTR lpszFamily, //
pointer to family-name string<BR> FONTENUMPROC
lpEnumFontFamProc,<BR> <BR>//
pointer to callback function<BR> LPARAM
lParam // pointer
to<BR>application-supplied data<BR>);<BR>其中的 FONTENUMPROC
lpEnumFontFamProc就是一個回調函數,該函數遵照格式<BR>int CALLBACK EnumFontFamProc( ENUMLOGFONT
FAR *lpelf, NEWTEXTMETRIC FAR<BR>*lpntm, int
FontType, LPARAM lParam )進行定義。<BR>如
同mutant所說,回調函數主要用于一些比較費時的操作,或響應不知道何時將會發生的事件,回調函數提供了一種異步的機制,相對于同步執行,提高了效
率.前者的例子如WriteFileEx,ReadFileEx等,函數的最后一個參數是一個回調函數的指針,程序中調用WriteFileEx以后,就<BR>直接返回了,可以繼續進行其他工作,系統在讀寫操作完成后通知程序作善后處理.后者的例子就是windows的事件機制回調函數的另一個用途,是用于一些
枚舉函數,如EnumDisplayModes等,每找到一種支持的顯示模式,就通知回調函數,由回調函數具體處理,這是因為<BR>EnumDisplayModes本身并不知道用戶要如何處理.能,用戶提供回調函數,定制系統的功能,這樣,不同的用戶提供不同的回調函數,可以使系統
具有不同的功能.這就是所謂的plugin.使用回調函數實際上就是在調用某個函數(通常是API函數)時,將自己的一個函數(這個函數為回調函數)的地<BR>址作為參數傳遞給那個函數。而那個函數在需要的時候,利用傳遞的地址調用回調函數,這時你可以利用這個機會在回調函數中處理消息或完成一定的操作。至于如
何定義回調函數,跟具體使用的API函數有關,一般在幫助中有說明回調函數的參數和返回值等。</P><BR>
<P><O:P></O:P></P><BR></DIV>
<DIV style="OVERFLOW-X: hidden; WIDTH: 85%"><IMG
src="什么是回調函數那_編程論壇.files/sigline.gif"><BR>做個有用的人!</DIV></DIV></DIV>
<DIV class=postbottom2>
<DIV class=postuserinfo style="HEIGHT: 24px">
<DIV style="FLOAT: left"><IMG style="MARGIN: 4px"
src="什么是回調函數那_編程論壇.files/ip.gif"></DIV>2006-3-26 21:04:00</DIV>
<DIV class=postie
style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; TEXT-INDENT: 10px; PADDING-TOP: 0px; HEIGHT: 24px">
<DIV style="FLOAT: right; MARGIN-RIGHT: 5px"><A
href="http://bbs.bc-cn.net/dispbbs.asp?boardID=55&ID=52123#top"><IMG
style="BORDER-TOP-WIDTH: 0px; MARGIN-TOP: 3px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px"
alt="" src="什么是回調函數那_編程論壇.files/p_up.gif"></A> </DIV>
<DIV></DIV></DIV></DIV><A name=77380></A><A id=l7 name=7></A>
<DIV class=postlary1>
<DIV class=postuserinfo>
<DIV
style="FILTER: glow(color='#A6BA98',strength='2'); FLOAT: left; MARGIN: 13px 0px 0px 2px; WIDTH: 123px; LINE-HEIGHT: 23px; HEIGHT: 27px"><FONT
color=#000066><B>wonglaye</B></FONT></DIV>
<DIV
style="FLOAT: left; MARGIN: 13px 0px 0px; WIDTH: 23px; TEXT-INDENT: 0px; LINE-HEIGHT: 23px; HEIGHT: 27px"><IMG
alt=帥哥喲,離線,有人找我嗎? src="什么是回調函數那_編程論壇.files/ofMale.gif"> </DIV>
<DIV style="MARGIN: 0px 0px 0px 24px"><IMG height=50
src="什么是回調函數那_編程論壇.files/54741.gif" width=50><BR><IMG
style="MARGIN: 1px 0px 2px"
src="什么是回調函數那_編程論壇.files/level0.gif"><BR>等級:新手上路<BR>文章:27<BR>積分:555<BR>注冊:2006年3月26日<BR></DIV></DIV>
<DIV class=postie>
<DIV class=dispbbs_hr>
<DIV style="FLOAT: right"><A title=下一樓 onclick=xl(8)
href="http://bbs.bc-cn.net/dispbbs.asp?boardID=55&ID=52123#8">第 <FONT
style="FONT-WEIGHT: bold; COLOR: red">7</FONT> 樓</A> </DIV> <A
href="mailto:me@wonglaye.net"><IMG alt=點擊這里發送電子郵件給wonglaye
src="什么是回調函數那_編程論壇.files/email.gif" align=middle border=0></A> <A
href="http://blog.wonglaye.net/" target=_blank><IMG alt=訪問wonglaye的主頁
src="什么是回調函數那_編程論壇.files/homepage.gif" align=middle border=0></A> </DIV>
<DIV
style="TEXT-INDENT: 0px; LINE-HEIGHT: 22px; PADDING-TOP: 5px; HEIGHT: 22px"><B></B></DIV>
<DIV
style="PADDING-RIGHT: 0px; MARGIN-TOP: 10px; FONT-SIZE: 9pt; OVERFLOW-X: hidden; WIDTH: 97%; WORD-BREAK: break-all; LINE-HEIGHT: normal; HEIGHT: 160px; WORD-WRAP: break-word">
<P>樓上這篇寫得不錯哦<IMG src="什么是回調函數那_編程論壇.files/em17.gif" align=middle
border=0><BR>初始化這篇帖子的luckbird所說的WinAPI是調用約定,同樣也是為了解決函數棧問題,比如參數入棧出棧的順序,怎樣清理推棧,調用約定分成好幾個,有cdecl,stdcall,fastcall等等,MFC默認的是cdecl,而你寫的Win32默認的是stdcall,在Win3.0時用PASCAL宏來聲明這個約定,而在Win32以后就用WinAPI或者APIENTRY來聲明stdcall了,這些調用約束在調試時經常會在調試窗口看到的。<BR>樓上的這篇真的不錯,還有那么一點文學味道,喜歡啊</P></DIV>
<DIV style="OVERFLOW-X: hidden; WIDTH: 85%"><IMG
src="什么是回調函數那_編程論壇.files/sigline.gif"><BR>freedom is not free to
gain</DIV></DIV></DIV>
<DIV class=postbottom1>
<DIV class=postuserinfo style="HEIGHT: 24px">
<DIV style="FLOAT: left"><IMG style="MARGIN: 4px"
src="什么是回調函數那_編程論壇.files/ip.gif"></DIV>2006-3-26 21:53:00</DIV>
<DIV class=postie
style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; TEXT-INDENT: 10px; PADDING-TOP: 0px; HEIGHT: 24px">
<DIV style="FLOAT: right; MARGIN-RIGHT: 5px"><A
href="http://bbs.bc-cn.net/dispbbs.asp?boardID=55&ID=52123#top"><IMG
style="BORDER-TOP-WIDTH: 0px; MARGIN-TOP: 3px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px"
alt="" src="什么是回調函數那_編程論壇.files/p_up.gif"></A> </DIV>
<DIV></DIV></DIV></DIV><A name=77527></A><A id=l8 name=8></A>
<DIV class=postlary2>
<DIV class=postuserinfo>
<DIV
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -