C/C++程式除錯和記憶體檢測

panf1989發表於2019-03-19

程式出現錯誤很正常,一個優秀的程式設計師必須學會除錯,發現錯誤並改正。減少程式錯誤最有效的方法是:在敲程式碼之前,多花點時間思考,如何構造程式,資料結構和演算法,儘量把細節提前寫下來,可以嘗試著在紙上寫出核心程式碼,這樣可以減少今後修改程式碼的時間。


1、常用的除錯技巧


(1)程式碼檢查,重新閱讀程式,排除比較明顯的錯誤。編譯時帶上 -Wall引數,生成所有的警告資訊。


gcc -Wall -pedantic -ansi   表示以ansi/iso生成所有的警告西資訊。


(2)取樣法: 在程式中增加一些程式碼,收集更多與程式執行時的行為相關的資訊。使用條件編譯,可以清楚的辨別哪些是除錯程式碼,有利於除錯後的程式碼整理。


例如:




#

ifdef

 DEBUG


  std :: cout  << x :
   # endif



程式編譯時可以選擇性的加上-DDEBUG。如果加上這個標誌,就定義了DEBUG這個符號,從而在程式中包含除錯用的額外程式碼,沒有加上該標誌,這些除錯程式碼將刪除。


(3)程式的受控執行。用偵錯程式來控制程式碼的執行,隨時檢視這些變數的狀態。


為了能夠除錯程式,需要在編譯和連結時為每個原始檔加上編譯選項引數。這些選項的作用是讓編譯器在程式中新增額外的除錯資訊。這些資訊包括符號和原始碼行號,偵錯程式將利用 這些資訊向使用者顯示程式已經執行到的原始碼的位置。 -g標誌 是對程式除錯性編譯時常用的一個選項。除錯資訊的加入使可執行程式的長度成倍的增長、容量增加,程式執行時的記憶體 數量還是和原來一樣,程式除錯結束後,最好還是將除錯資訊從程式的發行版中刪除。


2、使用gdb進行程式除錯


常用功能命令:


g++ -g -o test test.cpp  //編譯時加上-g引數


1、啟動gdb: gdb test

2、help

3、具備帶有歷史記錄的命令列編輯功能,方向鍵選擇之前執行過的命令,直接Enter鍵再次執行最近執行過的那條命令。單步除錯非常有用。

4、quit:退出

5、run:執行這個程式,程式執行失敗時gdb會報告失敗的原因和位置。

6、backtrace(bt):棧跟蹤,失敗時停止的位置,幫助我們找到程式到達錯誤地點的路徑。

7、print:run 後檢查變數,注意變數的生命期。

8、列印圍繞當前位置前後的一段程式碼,繼續使用list可以顯示更多的程式碼。

9、設定斷點,停止程式的執行,檢視變數。help breakpoint,break lineNumber,cont,end,display,disable breakpoint number,clear,commands breakpointNumber.  

10、設定斷點後經常使用單步除錯命令next(n),檢視程式執行的細節。 


3、valgrind記憶體除錯


動態記憶體分配很容易出現程式漏洞,必須清楚自己分配的每一塊記憶體,而且要確定沒有使用已經釋放的記憶體塊,非常重要。記憶體除錯的工具有很多,這裡使用的是valgrind工具。在centos 7中直接使用 yum install valgrind 安裝。




#

include

 

<iostream>




int   main ()
{
     int  *ptr =  new   int  [ 3 ];
    ptr[ 3 ]= 1 ;

     delete  [] ptr;
     std :: cout  << ptr[ 1 ];
     return   ;
}


上面簡單的程式碼編譯執行不會發生錯誤,但是實際上發生了很嚴重的記憶體問題。ptr[3]訪問越界,std::cout <<ptr[i],讀已經釋放過的記憶體。


透過valgrind工具可以檢查出來:


[xgwang@localhost Desktop]$ g++ -g -o test2 test2.cpp

[xgwang@localhost Desktop]$ valgrind ./test2

==21739== Memcheck, a memory error detector
==21739== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21739== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==21739== Command: ./test2
==21739== 
==21739==
  Invalid write of size 4
==21739== at 0x40081E: main (test2.cpp:8)
==21739== Address 0x5a1504c is 0 bytes after a block of size 12 alloc'd
==21739== at 0x4C2A7AA: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21739== by 0x400811: main (test2.cpp:7)

==21739== 
==21739== 
Invalid read of size 4
==21739== at 0x40083F: main (test2.cpp:11)
==21739== Address 0x5a15044 is 4 bytes inside a block of size 12 free'd
==21739== at 0x4C2B5E1: operator delete[](void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==21739== by 0x400836: main (test2.cpp:10)
==21739== 

0==21739== 
==21739== HEAP SUMMARY:
==21739== in use at exit: 0 bytes in 0 blocks
==21739== total heap usage: 1 allocs, 1 frees, 12 bytes allocated
==21739== 
==21739== All heap blocks were freed -- no leaks are possible
==21739== 
==21739== For counts of detected and suppressed errors, rerun with: -v
==21739== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31554652/viewspace-2638754/,如需轉載,請註明出處,否則將追究法律責任。

相關文章