1. 程式人生 > >VC++6_0除錯篇:變數的觀察--watch視窗的技巧

VC++6_0除錯篇:變數的觀察--watch視窗的技巧



       寫一下VC6的watch視窗的一些小技巧,對於除錯過程是非常有幫助的。VC6年紀已經很大了,微軟好像也不再支援,但是還是有很多人在用。我本人是非常喜歡它的小巧(相對vs2003,2005),佔資源少,即使這樣它的除錯功能仍然超級強,真是不錯。 
       好,廢話到此結束,下面貼程式碼來說明:

#include <stdio.h> #include <windows.h> 
class AutoExpand { public: 
 AutoExpand(int val, char* pval) { 
 a = val; p = pval; } private: int a; char *p; }; 
class CantExpand { public: 
 CantExpand(int val, char* pval) { 
 a = val; p = pval; } private: int a; char *p; }; 
int main(void) { 
 int p[4] = {0x31,0x32,0x33,0x34}; int *a = p; 
 FILE* fp = fopen("File Not Exist", "r"); DWORD dwError = GetLastError(); 
 AutoExpand ae(10, "abc"); CantExpand ce(10, "abc"); 
 return 0; } 

        上面程式碼中出現的變數先說明一下: 
      p: 是整形陣列,含四個元素,總共16Byte。        a: 整形指標,指向陣列p
      fp: 檔案指標,用來標識開啟的"File Not Exist",我機器裡是沒這個檔案的。
      dwError: 獲得fopen失敗的錯誤碼。一般來說可以用FormatMessge來格式化這個錯誤原因或者直接用VC自帶的工具errorlookup來查詢這個錯誤碼的解釋。

      ae和ce: 是自定義的AutoExpand型別的變數和CantExpand型別的變數。注意,這兩種型別只有型別名字不同。     下面看一下我在除錯這個程式的時候,watch視窗的顯示:
 
上圖中,左邊是Context視窗的Locals頁,顯示所有區域性變數。右邊是Watch視窗,是我自己新增的要觀察的物件。 好,先看看整形陣列p。我們看到Context視窗的顯示p其實只顯示了陣列的地址,點了+號展開後,顯示出了4個整形資料。而右邊視窗,我添加了一個p,c。p後面加個",c"是什麼意思呢?看看效果,p,c下面的[0],[1],[2],[3]顯示的是這4個整形值對應的ascii字元哈。所以從這裡有了第一個小技巧:
1.watch視窗中,在整形變數後面加上",c"可以顯示該變數對應的ASCII字元。實際上,可以直接敲數字這麼顯示也行。比如上面右邊視窗中的118,c的對應值是'v'。也就是說118對應的ASCII字元是'v'。那麼,反過來,要知道一個字元的ASCII碼值怎麼看呢?看上面,'v',d就是顯示字元'v'對應的十進位制ASCII碼值是118。 'v',x顯示的是對應的十六進位制的ASCII碼值。除了",c"   ",d"   ",x"外,還有一些其他的引數可以加,見後面的附表。
然後我們看看變數a. a是個指標。看左邊視窗,即使點了它的+號展開,也只看到了它指向的地址的第一個元素(49).如果想要看得更多的資料,也可以像我一樣,在上面的Memory窗口裡看。但是Memory視窗只有一個,要看多個指標指向的資料就麻煩了,切來切去。那就在watch視窗中顯示吧,a,4就可以了,看到我的watch視窗的顯示沒?所以,有了第二個小技巧:
2.watch視窗中,把指標當成陣列看,只要在指標名後面加上一個長度,就可以想看陣列一樣看到對應的資料了。比如我上面的a,4。那麼如果一個指標指向的資料很大,比如一個整形指標a是指向一個1000個整數的大塊記憶體,我只想看看最後4個數據,要怎樣呢?那就 (a+996),4 唄。從第996個數據開始,看4個~
接下來這個小技巧是我最喜歡的一個了。除錯中遇到系統函式呼叫失敗的情況,通常都要加上GetLastError()函式獲得返回值,然後查對應的解釋才知道錯誤原因。比如,我上面的程式碼要開啟一個不存在的檔案,結果fopen失敗。取回了錯誤碼dwError=2,一查才知道是檔案不存在。那麼可不可以不用查,偵錯程式直接告訴我原因呢?當然可以,不然我寫這幹嘛!剛才的錯誤碼2是記錄在dwError中了,所以只要在watch視窗看看dwError,hr 看value欄:系統找不到指定的檔案!爽吧!總結一下,第三個小技巧:
3. 在watch視窗中察看錯誤原因,只需要在錯誤之後面頰上",hr"就可以了。比如我上面的 dwError,hr 和 2, hr 都能夠顯示錯誤訊息。想看某個錯誤碼的解釋,只要後面加上",hr"就輕鬆搞定,非常方便!這裡還要提一下的是,即使不呼叫GetLastError()也是可以看錯誤原因的。在fopen()呼叫完後,直接在watch視窗敲 err,hr 也可以顯示最近一次的錯誤原因。但是我機器重新裝了os,還沒裝vc,現在用的還是安裝前的屍體。所以這個err,hr的顯示有問題。不過還是有應對之法,那就是強大的TIB資訊。watch視窗看看*(unsigned long*)(TIB+0x34), hr也是一樣的。至於為什麼嗎,那就是GetLastError的機制了。

 還剩2個變數,ae和ce。這兩變數型別名不同,但是其他全都一樣。為什麼這兩個變數在watch視窗中顯示的不一樣呢?ae直接顯示出了類成員的值,ce就顯示了個......嗯,這就是最後一個小技巧:
4. 在vc安裝目錄的msdev\bin目錄下有個autoexp.dat檔案。可以在裡面自定義資料的顯示。具體的看看它前面的大段說明,說得很詳細。我就是在檔案後面加上一行AutoExpand =int_val=<a,d> sz_val=<p,s>。 附表:
下表說明偵錯程式可識別的格式說明符。
說明符 格式

顯示
d,i signed 十進位制整數 0xF000F065 -268373915 u unsigned 十進位制整數 0x0065 101 o unsigned 八進位制整數 0xF065
0170145
x,X 十六進位制整數
61541(十進位制) 0x0000F065 l,h 用於 d、i、u、o、x、X 的 long 或 short 字首 00406042,hx 0x0c22 f signed 浮點型 3./2. 1.500000 e signed 科學計數法
3./2. 1.500000e+000 g signed 浮點型或 signed 科學計數法,無論哪個都更短 3./2. 1.5 c 單個字元 0x0065 101 'e' s 字串
0x0012fde8 "Hello world" su Unicode 字串
 
"Hello world"
hr
HRESULT 或 Win32 錯誤程式碼。(偵錯程式自動將 HRESULT 解碼,因此這些情況下不需要該說明符。
0x00000000L S_OK wc 視窗類標誌。 0x00000040  WC_DEFAULTCHAR wm Windows 訊息數字
0x0010
WM_CLOSE
下表包含用於記憶體位置的格式化符號。
符號
格式
顯示
ma 64 個 ASCII 字元
0x0012ffac .4...0...".0W&.......1W&.0.:W..1...."..1.JO&.1.2.."..1...0y....1
m 以十六進位制表示的 16 個位元組,後跟 16 個 ASCII 字元
0x0012ffac B3 34 CB 00 84 30 94 80 FF 22 8A 30 57 26 00 00 .4...0...".0W&..
mb 以十六進位制表示的 16 個位元組,後跟 16 個 ASCII 字元 0x0012ffac B3 34 CB 00 84 30 94 80 FF 22 8A 30 57 26 00 00 .4...0...".0W&..
mw 8 個字 0x0012ffac 34B3 00CB 3084 8094 22FF 308A 2657 0000 md 4 個雙倍字長 0x0012ffac 00CB34B3 80943084 308A22FF 00002657 mq 2 個四倍字長
0x0012ffac 7ffdf00000000000 5f441a790012fdd4 mu 2 位元組字元 (Unicode)
0x0012fc60 8478 77f4 ffff ffff 0000 0000 0000 0000
可以使用帶有計算為位置的任何值或表示式的記憶體位置說明符。