新世代高手
美國卡內基美隆大㈻碩士 林建仁 著
基礎篇
NET Visual C#
臭蟲,「走哪裡去!」
除錯環境基本教練
預估修行時間:2 小時
相信大部分的程式設計師都有過這樣的經驗:在某個身邊「所有的」朋友都出去玩的
夜裡,獨自一人坐在電腦螢幕前面,絞盡腦汁與程式中的蟲兒打一場不知何時結束又
無法和談的戰。有人一路揚威耀武地兼自信滿滿吆喝:「臭蟲,走哪裡去!」,抓起蟲
來又快又狠又準。也有人自始至終苦苦哀求:「親愛的蟲兒,求求你出來吧!別折磨我
了…」,日子似乎永遠沒有明天。你,我們的讀者,屬於哪一種?
當然,我們希望你是第一種程式師,對蟲兒是吆喝而不是哀求,至少,在寫 Visual C#
程式時是如此。想要有這種吆喝的功力,沒有好的除錯環境幫忙是很難達到的,這也
是本章的主題—Visual C#所提供的除錯環境。
在程式寫作上身經百戰的你一定明白,要一口氣完成一個像樣的程式而不經除錯階
段,簡直是神話!由於初學者剛開始都是按書照本宣科,碰到的程式都是作者親手料
理包裝,讀者只要乖乖張嘴吞下就行了,用到除錯器的需求性實在不高;然而隨著內
容逐漸深入,程式的規模愈來愈可觀,缺了除錯器便顯得捉襟見絀。
第五章
除錯環境基本教練
3
第五章
再者,除錯器除了抓蟲外也可以幫助程式員追蹤程式,確實了解程式的
行為。舉例來說,作者喜歡「好好利用」用餐完畢肚脹未消的時間來看
書,看著看著,常常按書本把程式打好了,也執行成功了,卻有不知其
所以然的感覺(通常是也不知不覺睡著了),此時如果使用除錯器一行一
行追蹤,學習效果大增。總之,它不僅是除錯的工具,也是學習的利器。
讓各位在進入物件導向的殿堂前,先熟悉除錯工具這項學習的利器,會
是學習上的一大福音。
我們將 Visual C#程式寫作會遇到的錯誤分為三大類:編譯時期錯誤
(Compile errors)、邏輯錯誤(Logic errors)、執行時期錯誤(Run-time
errors),分別告訴你如何用整合環境裡所提供的除錯器來幫你鎖定這些
臭蟲並試著一網打盡,同時,也會提出一些經驗與建議,預防勝於治療,
盡量避免你成為「養蟲大戶」;肺腑之語,叟言無忌,還望諸君細讀之!
編譯時期的錯誤(Complie Errors) 顧名思義之,編譯時期的錯誤來自程式建造編譯時期,例如,你可能打字時手指臨時脫臼把關鍵字打錯(if 打成 IF);或者,程式語法使用錯誤(這可多了,比如該有括號沒打括號,忘了加上「;」…);總之,凡是造成 Visual C#編譯時的困擾、讓它看不懂你在說些啥麼東西的,通通算是編譯時期的錯誤。
圖 5-1 編譯時期的錯誤,「txtDisplay.Text = “”」後面應該有「;」。
臭蟲,「走哪裡去!」
第五章
4
如何處理編譯時期的錯誤 修正編譯時期錯誤,是讓程式能執行之前最基本的動作,跟其他兩種錯誤比較起來,算是最容易解決的。Visual C#提供了幾樣工具來幫忙你揪出它們﹕
語法檢查。Visual C#編譯器會在背後為我們作程式語法的檢查。這項功能可以讓你及早發現語法或是打字上的錯誤,一但她發現程式碼中有不對勁的地方,藍色毛毛蟲狀底線便會出來提醒。
如圖 5-1,程式師在輸入「txtDisplay = “”」之後,尚未輸入「;」,藍色毛毛蟲出現在等號處。當我們把滑鼠移到藍色底線下,會有自動提示字串告訴我們錯誤的原因,對於每一個藍色底線,在「工作清單」視窗中會有相對的工作敘述:
圖 5-2 工作清單視窗忠實地紀錄每一條毛毛蟲的發源地。
妳可以在工作清單視窗中,雙擊工作項目,整合環境會把妳帶到錯誤所發生的程式碼。在妳修改程式碼之後,工作項目會自動消失。
邏輯錯誤 規規矩矩地把程式正確無誤地寫好、編譯,都通過了;於是,興高采烈地執行,啊,發現出來的結果不是我想要的—邏輯錯誤發生了!無奈地搖搖頭,伸個懶腰對自己笑笑,就近找杯咖啡來喝,稍息後重新來過,準備藉著測試程式與分析結果來捉臭蟲了。
Visual C#所提供的除錯環境至此正式派上用場,要進行除錯大業,勢必先瞭解 Visual C#的三種模式,底下讓我們逐步介紹。
除錯環境基本教練
5
第五章
Visual C#的三種模式 所謂的 Visual C#三種模式指的就是設計、執行與中斷。我們在設計模式下製作畫面、加程式碼;在執行模式下跑程式;這兩種模式大家都已經熟悉;至於中斷模式呢?它,就是專門除錯用的;想要利用 Visual C#所提供的除錯工具進行除錯的工作,必須先把 Visual C#切換到中斷模式。﹙ 怎麼切換到中斷模式?想想看!﹚
記得在第二章提到的「殿前五虎大將軍」中的抬頭列嗎?程式師可以很清楚的從抬頭列中得知現在正處於什麼模式。當我們製作畫面時,可以在抬頭列上看到「設計」的字眼,表示我們處於設計模式。當我們按下「開始」執行程式,可以在抬頭列上看到「執行」的字眼,表示我們處於執行模式。
「中斷」模式可以說是除錯專用的模式,當我們利用除錯環境要一步步追蹤程式碼,一個個檢視變數,都必須在中斷模式下才能使用。
圖 5-3 Visual C#三種不同的模式
如果在中斷及執行模式中修改程式碼,必須重新啟動程式後,修改才會產生效用。
臭蟲,「走哪裡去!」
第五章
6
「說哈囉」程式與除錯環境的初體驗 讓我們回到甜蜜的「說哈囉」程式,這一次,她將是我們與除錯環境初體驗的媒介,妳會在這個初體驗中,感受到除錯環境的強大功能。
設定㆗斷點
打開「說哈囉」方案。打開 frmHello 的程式碼視窗。我們準備在btnHello_Click 函式中,設定一個中斷點。中斷點會讓程式在中斷點處,進入中斷模式,很多除錯工具就可一顯身手了。
將滑鼠移到欲㆗斷程式碼之前端 ,單擊㆒次即可;再單擊㆒次可把㆗斷點取消。
㆗斷點在程式碼視窗㆗以紅色背景顯示
圖 5-4 設定中斷點
在圖 5-4 中,我們把「txtDisplay.Text = “哈囉, Visual C#”;」設定為中斷點,當程式執行到此行程式碼時,會自動進入中斷模式。妳也可以使用「F9」鍵來設定中斷點,請先將游標移到欲設定中斷點處,按下「F9」設定之,再按下一次「F9」可解除該中斷點之設定。
請依圖 5-4 再設定另外兩個中斷點,設定完成後如圖 5-5。
除錯環境基本教練
7
第五章
圖 5-5 設定三個中斷點
如果妳將中斷點設定在註解處,整合環境會告訴妳「這不是中斷點的有效位置」,因為註解並不實際產生機器碼,除錯器無法在此中斷。
按下「 」或 F5 執行程式,「說哈囉」視窗出現,我們知道當「說哈囉」按鈕被按下時,btnHello_Click 會被執行,可以碰上圖 5-5 中最上面的中斷點,請按下「說哈囉」按鈕。
圖 5-6 程式在「btnHello_Click」中進入中斷模式
臭蟲,「走哪裡去!」
第五章
8
㆔種不同的「㆒行㆒行」執行方式
進入中斷模式的主要目的,是要找出有問題的程式碼,中斷模式可以讓我們一行一行執行,一路觀察變數的值如何變化,找出錯誤的大本營而更正之。圖 5-7 中的「逐步執行」、「不進入函式」與「跳離函式」是三種讓我們一行一行執行的工具。
逐步執行﹙Step Into﹚
不進入函式
﹙Step Over﹚
跳出函式﹙Step Out﹚
圖 5-7 偵錯工具列
除錯工具 熱鍵 功能
逐步執行﹙Step Into﹚ F11 ㆒次執行㆒行程式碼,如
果遇到程序,則深入程序
㆗㆒行㆒行執行。
不進入函式﹙Step Over﹚ Shift-F0 跟逐步執行很像,㆒次執
行㆒行程式碼;不同在於﹕
遇到程序時它會把整個程
序當成㆒行敘述來看,不
會深入程序內部執行。
跳出函式﹙Step Out﹚ Shift-F11 當你使用「逐步執行」深
入某程序內部,尚未「逐
步執行」完而想跳出該程
序時,可以使用「跳出函
式」。
請分別試試三種除錯工具,在 btnHello_Click 程序中,「逐步執行」與「不進入函式」結果是相同的,因為沒有其他函式可供進入。如果妳按下「跳出函式」,「}」敘述會被跳過。我們建議各位把熱鍵記下來,在除錯時,熱鍵在使用上非常方便。在逐步執行的過程中,妳也可以隨時按下「 」鍵,繼續程式的運行(直到下個中斷點再停止),或按下「 」鍵,重新啟動程式。
除錯環境基本教練
9
第五章
顯示㆘個執行的敘述
請將程式中斷在「btnHello_Click」中,將滑鼠移到「 」所在之處。黃色箭頭所指的,是「下個執行敘述」,在此按下滑鼠右鍵叫出功能表,如圖 5-8,妳會看到很多除錯指令。如果妳夠細心,會發現右鍵功能表會依滑鼠游標所在不同,而有所不同。在圖 5-8 中,妳可以用右鍵功能表來移除、停用中斷點,如果滑鼠所在是個沒有中斷點的地方,這些項目就不會出現。
圖 5-8 在中斷處的除錯功能表
圖 5-8 的功能表有幾個地方值得一提。
臭蟲,「走哪裡去!」
第五章
10
「執行至游標處」:要求 Visual C#執行到目前滑鼠游標之處,接著進入中斷階段。通常我們用它來跳過一些我們認為沒必要追蹤除錯的地方,好比說以「逐步執行」追蹤時遇到一個執行一千次的迴圈,如果一次一次跑難保不神經虛脫,於是可以把游標移到迴圈外的敘述,以滑鼠右鍵叫出功能表,要求「執行至游標處」就行了。
「設定下一個陳述式」:我們可以用它來指定下一行要執行的敘述。先把滑鼠游標移到欲指定的敘述,以滑鼠右鍵請出「設定下一個陳述式」就行了。你將發現程式的控制權轉移到游標所在,看起來跟「執行至游標處」很像。
注意!「執行至游標處」會把起始點到滑鼠游標所在之間的所有敘述全部執行,而「設定下個執行點」是「跳過」起始點與滑鼠游標所在﹙ 也就是你所設定的下個執行點﹚ 之間的程式碼。換言之,當你以這個功能設定了下個執行點之後,Visual C#會直接跳過中間所有的敘述不執行。
㉂動變數、區域變數與㈼看式
繼續我們初體驗的旅程,這次請各位按下「說哈囉」的「清除」按鈕,讓程式中斷在「btnClear_Click」程序裡。讓程式中斷一個主要的目的,是要監控變數值,瞧瞧哪個變數值在作怪。在進入中斷模式後,觀察變數值最簡單的方法,就是把游標移到所欲觀察的變數旁邊,自動提示字串會告訴我們變數值,如圖 5-9。
圖 5-9 自動提示字串顯示變數值
Visual C#提供了自動變數、區域變數、與監看式三個視窗,方便我們作監控的動作。自動變數視窗是 Visual C#在目前的中斷點,自動為我們挑的變數,在圖 5-10 中,包含了 Visual C#自動為我們放入的變數。
除錯環境基本教練
11
第五章
圖 5-10 自動變數視窗
區域變數顯示跟目前中斷處相同視界(Scope)的變數,在區域變數中,我們有「this」、「sender」及「e」;「this」是 Visual C#的保留字,代表表單本身,「sender」與「e」是事件處理程序所傳入的兩個變數。區域變數視窗中的變數,也是自動填入的。(別忘了把物件名稱前面的小箭頭,展開瞧個究竟)
監看式與其他兩個視窗相似,不同於,監看式視窗中的變數是使用者自己填入的,自己填入的好處是,這些變數自始至終都存在,不會因為中斷點或函式視界改變而有所變動,對於監看整體變數很有用。
要在監看式視窗中加入變數,將滑鼠移到視窗中之空白列,單擊一下,就可輸入了,圖 5-11 中正在輸入 btnHello 變數。按下「Enter」鍵後,整個物件的資料都可一目了然。
圖 5-11 監看式視窗
利用㉂動變數、區域變數與㈼看式視窗更改變數值
在中斷模式下,自動變數、區域變數及監看式視窗,除了讓我們光明正大偷窺變數值之外,也可以修改變數值。要霸王硬上弓,請選擇欲修改的值,以滑鼠左鍵雙擊之,輸入新值,按下「Enter」鍵,被修改的值會以紅色顯示。
臭蟲,「走哪裡去!」
第五章
12
㆗斷點視窗
在自動變數、區域變數與監看式視窗這三口組隔壁,有個與之相互輝映的「中斷點視窗」,如圖 5-12 所示。
圖 5-12 中斷點視窗
在中斷點視窗中,會列出專案中的所有中斷點,現在我的程式碼還中斷在「btnClear_Click」,也就是第三個中斷點,妳可以發現,目前程式所在的中斷點會以粗體字型顯示。圖 5-12 之中斷點視窗可以讓我們做很多事,咱們先從表面來說。
在「名稱」底下的箭頭,表示此中斷點是否「啟用」,底下是「啟用」中斷點與「停用」中斷點的區別:
「啟用」之中斷點:中斷點存在,程式執行至此中斷。圖 5-12 中的三個中斷點都是啟用的,她們以紅色實心圓表示。在中斷點視窗中,「名稱」欄位下有勾勾的中斷點都是啟用的中斷點。
「停用」之中斷點:中斷點存在,但程式執行至此不中斷。停用之中斷點以空心的紅色空心圓表示。「名稱」欄位下沒有勾勾的中斷點都是停用的中斷點。
「欄」右邊有個小箭頭,可以設定顯示在中斷點視窗上的資訊。「叫用次數」表示從開始除錯的現在,停在這個中斷點幾次。以圖 5-12 為例,第一個中斷點是在 btnHello_Click 中的中斷點,因為我分別以「逐步執行」、「不進入函式」與「跳出函式」三種方式各跑了一次,所以叫用次數為三。第三個中斷點是 btnClear_Click 中的中斷點,也是程式目前中斷之處,這是第一次進入此中斷點。
除錯環境基本教練
13
第五章
結束初體驗
我們與「說哈囉」的除錯初體驗到此進行得差不多了。請把 btnExit_Click中的中斷點「停用」,按下「 」繼續程式執行,等程式畫面出現後,按下「結束」鈕結束這趟旅程。
「嘿!想捉我,最好乖乖進入中斷模式!」 抓蟲是種學習的過程與經驗的累積,高竿的人三兩下清潔溜溜,當然,也有養蟲大戶抓了半天卻見蟲兒愈加猖獗愈加興旺、世代綿延香火不斷的情形。抓蟲的需求來自於程式的運作情形跟我們的想法不同,首先,必須比較程式結果與我們心中預期的結果,從兩者的不同處分析比較,找出有可能出錯的地方,在那些地方設定中斷點,讓程式執行到該處時進入中斷模式,我們就可以在該處利用除錯工具來抓蟲。
要除蟲非得進中斷模式不可,Visual C#除了讓我們設定中斷點外,針對每一個中斷點,還提供了底下幾種不同的中斷方法。
設定不同的㆗斷時機
利用中斷點屬性頁可以設定每個中斷點中斷的時機。妳可以由圖 5-8 之功能表,選「中斷點屬性」請出中斷點屬性頁,如圖 5-13 所示:
圖 5-13 中斷點屬性頁
臭蟲,「走哪裡去!」
第五章
14
中斷點屬性頁的上半部,顯示中斷點的所在位置,可以以「檔案」、「函式」或記憶體「位址」等三種不同的角度來顯示。屬性頁的下半部,可讓我們藉由中斷「條件」與「叫用次數」的設定,來改變程式進入該中斷點的時機。
以「條件」設定進入該㆗斷點時機
按下圖 5-13 中的「條件」鈕,Visual C#提供了兩種設定條件的方式:
圖 5-14 設定中斷點條件
「為 True」:程式師必須在圖 5-14 之文字方塊填入條件運算式,當運算是由 False 改變為 True 時,程式才在該中斷點進入中斷。請看下例:
// ㆒個執行㆒千次的迴圈
for (int i=0; i<1000; i++)
{
…(略)
Result = Cal(X, Y);
}
如果我們希望將程式中斷在第九百九十九個迴圈,觀察此時的 Result 變數值,怎麼辦?難道要使用 F11(逐步執行),自己追蹤這個迴圈九百九十九次嗎?如圖 5-14 所示,當 Visual C#偵測到「I=999」成立時,會自動在變數「I」所在的程序中進入中斷模式,我們便可以觀察程序中其他變數的值。
除錯環境基本教練
15
第五章
「已變更」:程式師必須在圖 5-14 之文字方塊填入運算式,當運算式的值改變,程式才進入中斷。這種監看方式之原理,與上一個「為True」之監看方式十分類似,但「已變更」可以應用的範圍更加廣泛。應用的時機很簡單,當我們覺得某個變數的值,一開始設定為五,程式執行中「應該」不變,不知道在什麼時候竟然變成了十,這時候,把這個變數填入圖 5-14 之文字方塊,並設定中斷條件為「已變更」,我們就可以抓到變數改變的剎那,進而找出作怪之所在了。
以「叫用次數」設定進入該㆗斷點時機
按下圖 5-13 中的「叫用次數」鈕,我們可以由「叫用次數」來設定在該中斷點中斷的時機。
圖 5-15 設定「叫用次數」
在圖 5-15 中,我要求除錯器在該中斷點叫用次數達 999 次後,才進入中斷,這與之前 for 迴圈的例子,有異曲同工之妙。
使用 Debug 物件與「輸出」視窗
Debug 物件與「輸出」視窗在 Visual C#除錯界裡算是組你濃我濃的角色,為什麼我把「老大」放在這麼後面呢?這麼做是從讀者的角度來考量的。對初學者而言,有「監看式」,有「逐步執行」,有「不進入函式」,有「執行至游標處」等等,蟲兒應該已經無所遁逃,乖乖繳械壯烈成仁矣!若把「Debug」太早搬出來說,似乎有練功不成、走火入魔的嫌疑。
底下讓我們來瞧瞧「Debug」與「輸出」視窗能為我們做些什麼!