讀古今文學網 > C語言解惑 > 13.6 使用集成環境提供的調試手段 >

13.6 使用集成環境提供的調試手段

本節以inchar.c為例,說明從設計到調試的全過程,以便學習。

13.6.1 一個簡單的實例

【例13.11】要求將從鍵盤上輸入的一個字符按下面格式輸出,下面是一個運行示範。


Input
:5
Your input is
:5
  

這是一個順序執行過程,輸入有提示信息,輸出增加了說明。下面是含有錯誤的C語言程序,用來演示編譯和排錯的過程。


//inchar.c
main
( 
)
{
   char ch
;
   printf
(\"input
:\"
);
   scanf
(\"%d\"
, ch
);
   printf
(\"Your input is
:%dn\"
, ch
);
}
  

13.6.2 編譯程序

假設工程名為myc,源程序名為inchar.c。詳細步驟不再贅述。

輸入程序,檢查輸入無誤之後,即可對程序進行編譯。這裡需要注意的一點是,初學者往往過分地依賴編譯器,不重視編譯運行之前的人工檢查。有很多的小錯誤,如拼寫錯誤等是完全可以自己檢查出來的。應當逐步培養自己的查錯能力。在編製大型軟件時,這一點顯得尤其重要。特別需要提醒的是,C語言的關鍵字在編輯窗裡是以與文字不同的顏色顯示的,如果它們也變成了相同顏色,說明這一行隱含了VC不能識別的符號。最常見的原因是混入中文不可見符號或者用中文符號代替英文符號,如中文逗號代替西文逗號。

對文件進行編譯。如圖13-1所示,操作命令已經加上所在文件的標識,所以其功能非常清楚。選擇編譯命令「Compile inchar.c」,編譯結果出現3個警告信息,如圖13-2所示。

圖13-1 工程組成信息及Build菜單

目前需要掌握的最基本的3個命令介紹如下。

(1)「Compile inchar.c」命令用來編譯文件inchar.c。如果不能通過,則不產生obj文件,並給出出錯信息。如果通過,產生inchar.obj文件,也可能給出警告信息。如果有警告信息,則說明程序有不妥之處,應該排除,直到無警告信息。需要注意的是,有警告信息時,產生的obj文件可能會有錯誤,不能產生exe文件,或者運行結果不正確。第一次調試程序時,一般都要使用這一命令檢查錯誤。編譯系統會給出出錯和警告的可能原因,這將有助於查錯。

(2)「Build myc.exe」命令在編譯文件inchar.c時,同時產生inchar.obj和myc.exe文件。如果程序有問題,又不影響產生obj文件的話,只顯示警告信息的數目,不顯示警告的內容,這是與「Compile inchar.c」命令的區別。另外,可執行文件不是以C的源程序文件名命名,而是以工程命名,所以產生的執行文件名是myc.exe,而不是inchar.exe。

(3)「Execute myc.exe」命令執行文件myc.exe。如果沒有myc.exe,則自動執行編譯程序產生myc.exe文件,然後執行myc.exe文件。

如果一開始就使用「Build myc.exe」命令,只給出有問題的信息,這時產生的執行文件可能得不到正確結果。一旦有了無錯誤信息的inchar.obj文件,就可以使用「Build myc.exe」命令產生myc.exe文件。

圖13-2 編譯信息

13.6.3 排錯

由圖13-2的警告信息可知,這個程序沒有錯誤信息,具有繼續產生執行文件的可能性。即使能產生執行文件,也能正常運行,但也應該養成排除所有警告信息的正確作風。由警告信息可以看出,程序沒有包含定義printf和scanf函數的頭文件,主函數的定義也不嚴格。假設將它改正為如下程序。


#include <stdio.h>
int main
( 
)
{
    char ch
;
    printf
(\"input
:\"
);
    scanf
(\"%d\"
, &ch
);
    printf
(\"Your input is
:%dn\"
, ch
);
    return 0
;
}
  

編譯正確,執行「Execute myc.exe」運行程序,如圖13-3所示,Windows彈出一個DOS窗口來運行DOS程序,按屏幕上的提示,按任意鍵即可返回開發環境。

假設輸入52,則輸出52,但輸入字符W時,程序輸出-52,證明程序不正確。所以不要只取一種情況驗證程序是否運行正確,應對各種可能的情況都進行驗證。

圖13-3 運行程序的DOS窗口及運行結果

可以啟用Debug,觀察表達式或變量的值,並設置斷點或單步運行程序。這個示例程序比較簡單,如圖13-4所示,單步運行程序,即可直接看到變量的值。如果要在右邊設置監視的變量,直接在Name欄下輸入變量名即可。

圖13-4 觀察變量在程序運行期間的變化情況

由此可見,雖然輸入字符w,但讀給變量ch的不是字符值,而是數字。scanf和printf語句的格式不對,應該改為%c。因為輸入數字,所以隱藏了這個錯誤。輸入數字時正確,輸入字符時錯誤。通過監視變量的變化情況,可以很容易地發現這是將格式符%c錯寫成格式符%d造成的。

修改後的正確程序如下:


#include <stdio.h>
void main
( 
)
{
   char ch
;
   printf
(\"input 
:\"
);
   scanf
(\"%c\"
, &ch
);
   printf
(\"Your input is
:%cn\"
, ch
);
}
  

由於在程序設計中錯誤總是難免的,因此調試也是必不可少的,所以應該盡快熟悉調試環境,而熟悉的唯一途徑就是多用。「實踐出真知」說的也正是這個道理。

13.6.4 基本調試命令簡介

1.設置和取消斷點

設置和取消斷點是通過選擇右鍵菜單來實現的。斷點是程序員在程序上做的標記,表示調試程序時,運行到該處應該暫停。如圖13-5所示,在要設置斷點處單擊選擇右鍵菜單命令「Insert/Remove Breakpoint」,在該行設置一個紅色圓點表示斷點。

圖13-5 設置和取消斷點示意圖

如果要取消斷點,在斷點行再次使用右鍵,則出現「Remove Breakpoint」和「Disable Breakpoint」兩個菜單命令。前一個表示將取消斷點(紅色圓點消失),後一個表示保留斷點,但暫時不起作用(程序執行時忽略這個斷點)。如果選擇後一命令,則紅色實心圓點的內部變成白色(圖13-5中的紅色圓圈),同時菜單命令變為「Enable Breakpoint」,以便將來選擇該命令恢復斷點。

可以在光標所在行直接使用F9功能鍵設置和取消斷點,也可以用它激活保留斷點,但設置保留斷點必須使用右鍵菜單。

2.調試控制

若未設置斷點,可按F10鍵(Step Over)進行調試,調試程序將停在main函數的開始處。一旦準備好程序,便可以開始調試,這時可使用其他所有功能。

可採用下述方法進行調試。

(1)一次執行一行,跳過一些函數,或單步調試所有函數。

(2)從當前位置執行到預先設立的斷點。

(3)從當前位置執行到光標所在位置。

上述方法可以選擇使用也可以混合使用。

如果對源程序作了修改,則應重新編譯,然後再進行調試。事實上,修改源程序後再用Step Over或Trace Into命令企圖再次調試時,VC將詢問用戶是否需要重新生成可執行文件。

3.調試命令和熱鍵

表13-1列出了用於調試菜單的幾個特別的調試命令和熱鍵。

表13-1 常用調試命令

4.變量窗口

在如圖13-4所示的程序窗口下面,左邊的窗口稱為變量窗口,用來顯示各個變量及其取值。變量窗口有3個選項卡,分別是「Auto」,「Locals」和「this」。我們經常要查看前兩個選項卡中的內容,這兩個選項卡的作用如表13-2所示。隨著程序的執行,如果選項卡中變量的值發生變化,則將它們用紅色顯示出來。

表13-2 變量窗口中的「Auto」與「Locals」選項卡

只要雙擊變量的值,就可以直接修改該變量的值。在調試時,可以很方便地改變變量的值,觀察它們的行為。

5.觀察窗口

在如圖13-4所示的程序窗口下面,右邊的窗口稱為觀察窗口。在變量窗口中,「Auto」和「Locals」選項卡中所顯示的變量並不是當前函數中所有有意義的變量,而且在兩個選項卡之間切換也不方便,所以常使用觀察窗口來顯示變量的值。

觀察窗口共有4個選項卡,每一個選項卡中都可以任意輸入變量。雙擊Name欄的空白處,即可輸入任意變量,其值顯示在Value欄中。雙擊變量的值,可以直接修改。

在觀察窗口中,還可以輸入一些簡單的表達式,如「y+25」,Value欄中則顯示這個表達式的值。

6.調試命令菜單

如圖13-6所示,「Bulid」菜單含有可供調試程序的子菜單。使用這些調試命令可進入程序調試狀態。

如圖13-7所示,進入調試狀態後,「Build」的位置被「Debug」菜單代替。圖13-7還給出了執行斷點行的示意圖。

圖13-6 Bulid菜單的調試命令

圖13-7 Debug菜單及執行斷點行的示意圖

13.6.5 程序與彙編調試窗口

有時需要根據彙編窗口加以觀察。下面的程序演示了內存數據的存放方式。

【例13.12】演示小端存儲的程序。


#include <stdio.h>
union s{
      int n
;
      char str[4]
;
}uc
;
int main
( 
)
{
     int i=0
;
     uc.n=0x12345678
;
     printf
(\"0x%xn\"
,&uc
);
     for
(i=0
;i<4
;i++
)
           printf
(\"0x%x 0x%xn\"
,&uc.str[i]
,uc.str[i]
);
     return 0
;
 }
 

從圖13-8的窗口可以看出,uc.str[0]存儲的是0x78,對照7位ASCII編碼表,0x78也是小寫字母x的ASCII碼。對比un.n=0x12345678,str[0]裡存儲的是0x78,也就是地址0x12345678的低端地址,又稱小端地址。0x56對應大寫字符V,0x34對應數字4,而0x12則是不可顯示字符,由此證明本機是小端存儲方式。

圖13-8 演示小端地址存儲方式示意圖

可以通過圖13-8中的下拉框Context選擇顯示內容。如圖13-9所示,mainCRTStartup顯示彙編代碼。也可以直接用Windows菜單裡在c文件和Disassembly之間選擇。

圖13-10是單步運行彙編程序示意圖。

圖13-9 Windows菜單c文件和Disassembly菜單項

圖13-10 單步運行彙編程序示意圖