前言
你是否遇到過以下情況?
情況一:為了除錯方便,程式碼中夾雜各種cout語句。當除錯好了,把這些語句刪了,執行“正式版”後,又發現新問題,只得把這些cout語句一個個新增回去再進行除錯。如此不斷迴圈。
情況二:希望在程式碼中獲取到原始檔的檔名,當前程式碼行號,編譯時間等資訊。
情況三:糾結於是否實現某些概率極低(幾乎不存在)的錯誤檢測
如果有,那麼這篇隨筆適合你,或者說,前處理器帶來的除錯技術適合你。
技巧一:設定除錯區程式碼開關
請看下面的原始碼:
1 #include <iostream> 2 3 using namespace std; 4 5 int main() 6 { 7 /* 8 * 原始碼區一 9 */ 10 11 #ifdef DEBUG1 12 cout << "DEBUG1" << endl; 13 #endif 14 15 /* 16 * 原始碼區二 17 */ 18 19 #ifdef DEBUG2 20 cout << "DEBUG2" << endl; 21 #endif 22 23 /* 24 * 原始碼區三 25 */ 26 27 return 0; 28 }
兩段包含cout語句的程式碼段都是除錯語句,而兩個巨集DEBUG1和DEBUG2就是所謂的開關。現在假設我想執行上面的那段除錯程式碼,則可以輸入以下指令開啟DEBUG1開關並完成編譯(這條命令等效於在原始檔開頭加上#define DEBUG1再編譯):
1 g++ -DDEBUG1 1.cpp -o run
執行結果如下:
結果顯示DEBUG1開關對應的除錯語句得到執行。可以用同樣的方法操縱開關DEBUG2及其對應除錯程式碼。明白了吧,你可以通過開啟開關自由地選擇需要編譯並執行的除錯區程式碼。
技巧二:使用預定義巨集獲取相關資訊
前處理器提供了一些預定義的巨集可獲取編譯,檔案的相關資訊,參見下面程式碼:
1 #include <iostream> 2 3 using namespace std; 4 5 int main() 6 { 7 cout << "檔名: " << __FILE__ << endl; 8 cout << "當前行號: " << __LINE__ << endl; 9 cout << "編譯日期: " << __DATE__ << endl; 10 cout << "編譯時間: " << __TIME__ << endl; 11 12 return 0; 13 }
執行結果:
技巧三:使用assert斷言巨集確保某個條件不發生
基本格式為 assert(表示式)。當表示式為真,語句不做任何事情,否則語句輸出錯誤並終止程式執行,請看下面程式碼:
1 #include <iostream> 2 #include <cassert> // 要使用assert斷言巨集必須包含這個標頭檔案 3 4 using namespace std; 5 6 int main() 7 { 8 int t=0; 9 cin >> t; 10 11 assert (t !=0); 12 cout << "t: " << t << endl; 13 14 return 0; 15 }
assert在這裡的作用是確保t不等於0。如果t=0,程式會彈出錯誤並停止執行。編譯程式碼並執行,
當輸入為0時執行結果:
當輸入其他數字時執行結果:
最後要強調的是,assert只是除錯工具,它絕對不能代替邏輯檢查參與到異常處理中。