国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Linux環(huán)境下的C/C++基礎調(diào)試技術1——初步了解 - gnuhpc的專欄 - CSD...
  Linux環(huán)境下的C/C++基礎調(diào)試技術1——初步了解 收藏 此文于2010-12-03被推薦到CSDN首頁
如何被推薦?
Author:gnuhpc
WebSite:blog.csdn.net/gnuhpc
1.調(diào)試技術的幾個準則
驚喜準則:找到錯誤是一種驚喜,心理上不要畏懼而是要懷著感恩的心去面對。
從小處開始準則:剛開始測試的使用從小處著手,暫時不涉及邊界數(shù)據(jù),雖然這樣可能會掩蓋一些Bug,但是這樣或許能查到最主要的Bug,例如你的程序包含了一個巨大的循環(huán)體,最容易發(fā)現(xiàn)的Bug在第一個循環(huán)或第二次循環(huán)執(zhí)行的時候。
自頂向下準則:優(yōu)先選擇step over而不是step into,以節(jié)省時間。
Segmentation Fault準則:出現(xiàn)段錯誤時,第一個想到的不應該是printf而是Debugger,因為在調(diào)試器中你能看到你的哪一行代碼導致了錯誤,更重要的是你可以通過backtrace等工具得到更多有用的信息。
折半查找準則:在尋找bug時可以充分利用編輯器等工具來進行折半查找,具體在后邊有例子說明。
2.Linux下代碼調(diào)試工具
主要使用的GDB,以及基于GDB的圖形化工具,如DDD或eclipse,選擇上看個人習慣了。
命令行式的GDB啟動較快,可以在ssh終端下使用,操作簡潔,并且在調(diào)試GUI程序時不會崩潰,但較之圖形化則在單步調(diào)試或設置斷點時非常不方便。
當然你可以使用Vim等編輯器的插件或者補丁(clewn or vimGDB)來彌補這一缺憾,并且在GDB6.1以上的版本你可以使用GDB -tui這個模式(或者在GDB的命令行模式下按CTRL-x-a)打開一個類似于圖形界面的文本界面模式,在這個界面中你可以使用上下鍵查看源代碼(CTRL-P 和 CTRL-N完成輸入過的命令的查看).
或者你還可以使用cGDB這個工具(很慶幸這個項目在停止了三年后又有人開始維護了),這個工具是將GDB用curses包裝了一下,提供了一些很好用的feature(Esc和i鍵在代碼和命令框間切換;在代碼框中支持vim型的操作;在命令框中支持tab鍵補全命令;在移動到想加入斷點的行(行號為高亮白色)直接用空格鍵,設定好后行號會變紅;)。另外,在調(diào)試C-S程序時推薦使用eclipse。
在本文中,重點介紹ddd的操作,因為這個工具即結合了GDB命令行和圖形界面的操作。其余請參閱各個工具的手冊。
3.GDB命令行最基本操作
設置斷點:b LineNumber
單步執(zhí)行:n(TIPs1:可以按回車重復上一次操作,在單步調(diào)試時這個feature很有用)。
單步進入:s
繼續(xù)執(zhí)行:c
設置臨時斷點:tb LineNumber 可以理解為一次性斷點,與斷點不同,臨時斷點只在第一次執(zhí)行時起作用。
查看變量:p
設置觀察點:
w Expression,當Expression是一個變量名時,這個變量變化時會停止執(zhí)行;你也可以使用條件來限定,比如w (z>28),當z大于28時,程序停止。注意觀察點一般使用在更大范圍上的變量,而不是本地變量,因為在局部變量上設置的觀察點在局部結束時(比如該變量所在的函數(shù)執(zhí)行結束時)就被取消了。
當然這并不包含main的情況,因為main函數(shù)執(zhí)行結束后程序就結束了。
查看棧幀:
棧幀指的是在一個函數(shù)調(diào)用時,該函數(shù)調(diào)用的運行信息(包含本地變量、參數(shù)以及函數(shù)被調(diào)用的位置)存儲的地方。每當一個函數(shù)被調(diào)用時,一個新的幀就被系統(tǒng)壓入一個由系統(tǒng)維護的幀,在這個棧的頂端是現(xiàn)在正在運行的函數(shù)信息,當該函數(shù)調(diào)用結束時被彈出并析構。
在GDB中,frame 0為當前幀,frame 1為當前幀的父幀,frame 2為父幀的父幀,等等,用down命令則是反向的。這是一個很有用的信息,因為在早期的一些幀中的信息可能會給你一些提示。
backtrace查看整個幀棧
注意:在幀中來回并不影響程序的執(zhí)行。
實例:插入排序算法調(diào)試
用偽代碼描述這個過程如下:
 
擬調(diào)試代碼如下:
//
// insertion sort,
//
// usage:  insert_sort num1 num2 num3 ..., where the numi are the numbers to
// be sorted
int x[10],  // input array
    y[10],  // workspace array 
    num_inputs,  // length of input array
    num_y = 0;  // current number of elements in y
void get_args(int ac, char **av)
{  int i;
   num_inputs = ac - 1;
   for (i = 0; i < num_inputs; i++)
      x[i] = atoi(av[i+1]);
}
void scoot_over(int jj)
{  int k;
   for (k = num_y-1; k > jj; k++)
      y[k] = y[k-1];
}
void insert(int new_y)
{  int j;
   if (num_y = 0)  { // y empty so far, easy case
      y[0] = new_y;
      return;
   }
   // need to insert just before the first y
   // element that new_y is less than
   for (j = 0; j < num_y; j++)  {
      if (new_y < y[j])  {
         // shift y[j], y[j+1],... rightward
         // before inserting new_y
         scoot_over(j);
         y[j] = new_y;
         return;
      }
   }
}
void process_data()
{
   for (num_y = 0; num_y < num_inputs; num_y++)
      // insert new y in the proper place
      // among y[0],...,y[num_y-1]
      insert(x[num_y]);
}
void print_results()
{  int i;
   for (i = 0; i < num_inputs; i++)
      printf("%d\n",y[i]);
}
int main(int argc, char ** argv)
{  get_args(argc,argv);
   process_data();
   print_results();
}
我們編譯一下:
gcc -g -Wall -o insert_sort ins.c
注意我們要使用-g選項告訴編譯器在可執(zhí)行文件中保存符號表——我們程序中變量和代碼對應的內(nèi)存地址。
現(xiàn)在我們開始運行一下,我們使用“從小處開始準則”,首先使用兩個數(shù)進行測試:
./insert_sort 12 5
我們發(fā)現(xiàn)該程序沒有退出,貌似進入了一個死循環(huán)。我們開始使用ddd調(diào)試這個程序:
ddd insert_sort
運行程序,傳入兩個參數(shù):
r 12 5
此時程序一直運行不退出,按Ctrl+C暫停程序的執(zhí)行
(GDB) r 12 5
^C
Program received signal SIGINT, Interrupt.
0x080484ff in insert (new_y=3) at insert_sort.c:45
/home/gnuhpc/MyCode/Debug/Chapter_01/insert_sort/pg_019/insert_sort.c:45:939:beg:0x80484ff
(GDB)
 
我們可以看到程序停止在第49行。我們看一下num_y現(xiàn)在的值:
(GDB) p num_y
$1 = 1
這里的$1指的是你要GDB告訴你的第一個變量。找到了這個地方后,我們看看在num_y=1時都發(fā)生了什么,我們在insert函數(shù)(第27行)設置斷點(你也可以直接使用break insert在這個函數(shù)的入口設置斷點),并且設置GDB在斷點1處(你可以通過info break命令查看斷點)只當num_y==1時才停止:
(GDB) b 27
Breakpoint 1 at 0x80484a1: file insert_sort.c, line 27.
(GDB) condition 1 num_y==1
(GDB) 
上述命令也可以使用break if合一:
(GDB) break 27 if num_y==1
然后再運行程序,隨后用n單步調(diào)試發(fā)現(xiàn)我們跳到了該函數(shù)的出口處:
 
此時我們看看num_y的值,以便查看到底這個for循環(huán)執(zhí)行的情況。
(GDB) p num_y
$2 = 0
此時的情況是我們進入這個函數(shù)時num_y為1,但是現(xiàn)在num_y為0,在中間這個變量被改變了。現(xiàn)在你知道Bug就在30-36行間。同時,通過單步調(diào)試你發(fā)現(xiàn)31-33行被跳過了,34、35行為注釋,那么Bug就在第30或第36行間了。
我們現(xiàn)在仔細看這兩行就能得出結論了:30行有個典型的if判斷條件寫成賦值的錯誤,致命的是這個變量是全局變量,直接導致49行的for循環(huán)變量一直被重置。我們修改后重新編譯(可以另開一個編輯器,不用退出ddd),然后再運行
(GDB) r 12 5
5
0
雖然沒有了死循環(huán),但是結果還是不對的。
請注意,初始的時候數(shù)組y是空的,在#49進行第一次循環(huán)時,y[0]應該為12,在第二個循環(huán)中,程序應該挪動12為5騰出位置插入,但是此時這個結果看上去是5取代了12。
此時單步調(diào)試進入for循環(huán),#37看y[0]的值,的確是12。我們執(zhí)行到scoot_over函數(shù)時,根據(jù)自頂向下準則我們單步跳過,繼續(xù)執(zhí)行到#41,看看結果對錯再決定是不是要單步進入scoot_over函數(shù):
 
我們發(fā)現(xiàn)12根本就沒有被移動,說明scoot_over函數(shù)有問題,我們?nèi)サ鬷nsert函數(shù)入口的斷點,在scoot_over入口處設置斷點,當num_y=1的時候終止:b scoot_over if num_y==1。進一步單步調(diào)試后發(fā)現(xiàn)這個#23的for循環(huán)就沒有執(zhí)行。
(GDB) p jj
$12 = 0
(GDB) p k
$13 = 0
我們看到是因為沒有滿足for循環(huán)條件而不能進入循環(huán)。在這里12應該從y[0]移動到y(tǒng)[1],那么我們確定是循環(huán)的初始化錯誤,應該為k = num_y,將這個地方修改后編譯運行,程序出現(xiàn)段錯誤。我們清空所有的斷點,然后在
(GDB) r
Program received signal SIGSEGV, Segmentation fault.
0x08048483 in scoot_over (jj=0) at insert_sort.c:24
(GDB)
這里指出在24行出現(xiàn)seg fault,那么要么k超過了數(shù)組界限,要么k-1為負的。打印一下k的值,我們就發(fā)現(xiàn):
(GDB) p k
$14 = 992
(GDB)
遠遠超過k應該有的值。查看num_y 為1,說明在處理第二個要排序的數(shù)時出錯,再打印jj值,發(fā)現(xiàn)為0,就發(fā)現(xiàn)我們的for循環(huán)k++應該改為k—。
編譯運行,發(fā)現(xiàn)ok。但是運行多個數(shù)據(jù)就又出錯了:
(GDB) r 12 5 19 22 6 1
1
5
6
12
0
0
Program exited with code 06.
(GDB)
我們看到結果中從19開始的排序都有問題,我們在for (j = 0; j < num_y; j++)  這一行行設置斷點,條件為new_y==19的時候:
(GDB) break 36 if new_y==19
Breakpoint 10 at 0x80484b1: file insert_sort.c, line 36.
(GDB)
單步調(diào)試就發(fā)現(xiàn)我們沒有對當要插入的元素大于所有元素時進行處理。在#44后加入y[num_y] = new_y;重新編譯,運行程序正確,至此,我們通過一個簡單的例子演示了一下如何使用GDB進行調(diào)試。
參考文獻:
《Art of Debugging》
《Linux® Debugging and Performance Tuning: Tips and Techniques》
Author:gnuhpc
WebSite:blog.csdn.net/gnuhpc
 
本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/gnuhpc/archive/2010/12/03/6051867.aspx
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
gdb常用命令 — Windows Live
linux下的C語言開發(fā)(gdb調(diào)試)
除錯專家---程序調(diào)試的利器GDB
Gdb調(diào)試精粹及使用實例
GDB 常用調(diào)試命令
用gdb調(diào)試C與C++程序
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服