釋出
2010年9月19日

除錯你的程式

評分:3.3/5 (27 票)
*****
除錯你的程式

我覺得這是一個需要詳細討論的話題。除錯是程式設計中一個非常重要的部分。如果你遇到錯誤,你需要知道如何找到問題並解決它。如果你只是缺少一個分號,你不應該為此發帖求助。
請記住,這並不是具體的除錯方法。它不是一套規則,而是一組建議。我的建議可能不一定是正確的做法。如果在本文中發現任何不正確的內容,請告知我,以便我進行更正。我不喜歡傳播錯誤的知識。

無論如何,我們將從基礎開始,從識別和理解編譯器錯誤,到使用 IDE 的偵錯程式單步執行程式。

請注意:我參考了 Stephen Randy Davis 編寫的《C++ for Dummies》第 5 版,第 139-155 頁。

識別錯誤

通常,你的程式不會按計劃工作,並且無法正確編譯。即使是最好的程式設計師也會犯錯誤,能夠識別你做錯了什麼是至關重要的。存在兩種型別的錯誤:C++ 編譯器可以自行捕獲的錯誤,以及編譯器無法捕獲的錯誤。C++ 可以捕獲的錯誤稱為編譯時錯誤。編譯時錯誤應該相對容易修復,因為編譯器會指出問題所在。編譯器輸出的所有垃圾資訊都有其用途。這是一個例子。我忘記在 return 語句後新增分號。
1
2
3
4
int main()
{
return 0
}

你的編譯器應該會生成類似這樣的錯誤…
\main.cpp(4) : error C2143: syntax error : missing ';' before '}' 編譯器錯誤因編譯器而異,但總體上都差不多。在我的例子中,我使用的是 Visual Studio 2008,但如果你使用的是 Dev-C++ 或 G++,情況也是一樣的。
現在讓我們分解一下這個編譯器錯誤。它的第一部分 \main.cpp(4) 表示錯誤在 main.cpp 檔案中,第 4 行。之後是 error C2143:,這是編譯器特定的錯誤程式碼。如果你使用的是 Visual Studio,如果需要,你可以很容易地在 MSDN 上查詢錯誤程式碼。之後,錯誤宣告 syntax error : ,這告訴你你弄亂了一些語法。所以你一定沒有正確輸入某些內容。然後它告訴我 missing ‘;’ before ‘}’ 在右括號前缺少一個分號。好的,我知道我缺少一個分號,我知道錯誤在第 4 行,我知道它在右括號之前。所以我轉到 main.cpp,第 4 行,在右括號之前我需要一個分號。由於第 4 行上唯一的東西是一個右括號,我只需向上移動到第 3 行,OH!我注意到我忘記在 return 0 之後新增分號。識別編譯器錯誤應該如此簡單。
C++ 無法捕獲的另一種型別的錯誤稱為執行時錯誤。執行時錯誤通常更難捕獲。

除錯技巧

除錯程式有幾種方法。我最常使用的兩種是 WRITE 技術和單步除錯。首先,我將介紹 WRITE 技術。它涉及為你所有的變數建立輸出語句,以便你可以檢視所有變數的值。我將使用《C++ for Dummies》第 5 版中的這個程式示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// ErrorProgram – This program averages a series
//		 of numbers, except that it contains
//		 a fatal bug.
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;

int main(int nNumberofArgs, char *pszArgs[])
{
	cout << "This program is designed to crash!"
		 << endl;

	int nSum;
	int nNums;

	// accumulate input numbers until the
	// user enteres a negative number, then
	// return the average
	nNums = 0;
	while(true)
	{
		// enter another number to add
		int nValue;
		cout << "Enter another number:";
		cin >> nValue;
		cout << endl;

		// if the input number is negative...
		if(nValue < 0)
		{
			// ... then output the average
			cout << "Average is: "
				 << nSum/nNums
				 << endl;
			break;
		}

		// not negative, add the value to
		// the accumulator
		nSum += nValue;
	}

	cin.ignore(10000, '\n');
	return 0;
}


執行此程式碼時,你會得到一個執行時錯誤。解決問題的簡單方法是使用 WRITE 技術。每次你進入 while 迴圈時,讓它輸出 nNums 的值。

1
2
3
4
5
6
7
While(true)
{
	// output
	cout << “nNums = “ << nNums << endl;
	
	// The rest of the program is unchanged
}


輸出將如下所示

This program is designed to crash!
nNums = 0
Enter another number:1

nNums = 0
Enter another number:2

nNums = 0
Enter another number:3

nNums = 0 
Enter another number:

你可以看到 nNums 被初始化為 0,但是它在哪裡遞增?沒有,這就是 bug。顯然 nNums 應該在輸入部分的每次迴圈中遞增。透過使用 WRITE 技術,我們告訴程式輸出每次迴圈中 nNums 的值,從而發現它沒有被正確遞增。

對於較小的程式,WRITE 技術效果很好,但是隨著程式變得更大,輸出所有變數變得更加困難,並且看起來只是浪費時間。相反,我們將依靠偵錯程式。首先,讓我們定義一個偵錯程式。偵錯程式是構建到大多數開發環境中的工具(儘管它們有所不同,但大多數偵錯程式的工作原理相同)。程式設計師透過與編輯器相同的介面,透過命令來控制偵錯程式。你可以在選單項中或使用熱鍵訪問這些命令。偵錯程式允許程式設計師控制他/她的程式的執行。他/她可以在程式中一次執行一個步驟,他/她可以在任何時候停止程式,並且他/她可以檢查變數的值。要體會偵錯程式的強大功能,你需要親眼目睹它的實際應用。用語言很難解釋(而且我不擅長用語言表達)。因此,有關除錯的更多資訊,我將連結到一個非常方便的網頁。 http://www.cprogramming.com/tutorial/debugging_concepts.html

如果有任何需要新增的內容,請告訴我。