Linux下C語言的調試

調試是每個程序員都會面臨的問題. 如何提高程序員的調試效率, 更好更快地定位程序中的問題從而加快程序開發的進度, 是大家共同面對的問題. 可能Windows用戶順口就會說出:用VC唄 :-) , 它提供了設置斷點, 單步跟蹤等的圖形界面, 使調試起來直觀易用. 但Linux用戶可能要生悶氣了 O:-) : 難道我們Linux程序員就只能使用原始的調試方法, 在代碼中加入printf信息嗎?難道Linux下就沒有好的C語言調試工具嗎?

當然不是了. GNU早就組織開發了一套C語言編譯器(Gcc)和調試工具(Gdb). Gdb雖然沒有圖形化的友好界面, 但是它強大的功能也足以與微軟的VC工具相媲美, 給Linux程序員帶來了福音. 下面通過一個簡單的例子, 演示一下Gdb的使用流程:

示例文件 demo.c 的源代碼如下:

#include <stdio.h>

int sum(int, int);

    int
main()
{
    int result;
    int a = 1, b = 2;
    result = sum(a, b);
    printf("%d + %d = %d\n", a, b, result);
    return 0;
}

    int
sum(int a, int b)
{
    return a + b;
}

編譯源文件, 生成可執行文件

$ gcc -g -Wall -o demo demo.c

雖然這段程序沒有錯誤, 但調試完全正確的程序可以更加了解Gdb的使用流程. 接下來就啓動Gdb進行調試.

注意:

  • Gdb進行調試的是可執行文件, 而不是”.c”源文件, 因此, 需要先通過Gcc編譯生成可執行文件才能用Gdb進行調試.
  • 一定要加上選項”-g”, 這樣編譯出的可執行代碼中才包含調試信息, 否則Gdb無法載入該可執行文件.
  • 不能使用 -O2選項對可執行文件進行優化, 因爲優化之後可執行文件裏的符號表信息將被刪除, 這樣Gdb就無法找到使可執行文件與源文件之間的關聯了, 也就不能調試了.

(1) 啓動Gdb

$ gdb demo
GNU gdb (GDB) 7.0-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/wangsheng/tmp/demo/gdb/demo...done.

可以看出, 在Gdb的啓動畫面中指出了Gdb的版本號, 使用的庫文件等頭信息, 接下來就進入了由”(gdb)”開頭的命令行界面了.

(2) 查看源文件

在Gdb中鍵入”l”(list的縮寫)可以查看所載入的文件, 如下所示:

(gdb) l
1       #include
2
3       int sum(int, int);
4
5           int
6       main()
7       {
8           int result;
9           int a = 1, b = 2;
10          result = sum(a, b);
(gdb) l
11          printf("%d + %d = %d\n", a, b, result);
12          return 0;
13      }
14
15          int
16      sum(int a, int b)
17      {
18          return a + b;
19      }
(gdb) l
Line number 20 out of range; demo.c has 19 lines.

可以看出, Gdb列出的源代碼中明確地給出了對應的行號, 這樣就可以大大地方便代碼的定位.

(3) 設置斷點

設置斷點是調試程序中一個非常重要的手段, 它可以使程序到一定位置暫停運行. 因此,可以在該位置方便地查看變量的值, 堆棧情況等, 從而找出代碼的癥結所在.

在Gdb中設置斷點非常簡單, 只需在”b”後加入對應的行號即可(這是最常用的方式). 如下所示:

(gdb) b 9
Breakpoint 2 at 0x4004f4: file demo.c, line 9.

注意: 該斷點的作用是當程序運行到第 9 行時暫停(第 8 行執行完畢, 第 9 行未執行)

(4) 查看斷點信息

(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004004f4 in main at demo.c:9

(5) 運行代碼

接下來就可運行代碼了, Gdb默認從首行開始運行代碼, 可鍵入”r”(run的縮寫)即可. 若想從程序中指定的行開始運行, 可在r後面加上行號.

(gdb) r
Starting program: /home/wangsheng/tmp/demo/gdb/demo

Breakpoint 2, main () at demo.c:9
9           int a = 1, b = 2;

可以看到程序運行到斷點處就停止了.

(6) 查看變量值
鍵入p(print的縮寫)+變量名即可查看該變量在此時的值

(gdb) p a
$1 = 1
(gdb) p b
$2 = 2
(gdb) p result
$3 = 32767

注意: 這裏之所以result是一個莫名其妙的值, 是因爲聲明result是沒有初始化, 其值是不固定的。

(7) 單步執行

單步運行可以使用n(next的縮寫)或者s(step的縮寫), 它們之間的區別在於: 若有函數調用的時候, s會進入該函數而n不會. 因此, s就類似於VC等工具中的”step in”, n就類似於VC等工具中的”step over”.

如果使用n命令顯示如下:

(gdb) n
10          result = sum(a, b);

下面使用 s 命令,跟蹤進入 sum 函數:

(gdb) s
sum (a=1, b=2) at demo.c:18
18          return a + b;

可以看出執行 s 命令時進入了sum函數內部, 如果用 n 命令則跳過函數的調用部分

(8) 恢復程序運行

在查看變量值以及堆棧之後, 就可以使用命令c(continue)恢復程序的正常運行了. 這時, 它會把剩餘還未執行的程序執行完, 並顯示剩餘程序的執行結果.

(gdb) c
Continuing.
1 + 2 = 3

Program exited normally.

可以看出, 程序在運行完後退出, 之後程序處於”停止狀態”.
說明: 在Gdb中, 程序的運行狀態有”運行”,”暫停”和”停止”3種. 其中”暫停”狀態是程序遇到了斷點或者觀察點, 程序暫時停止運行, 而此時函數的地址, 函數參數, 函數內的局部變量都會被壓入”棧(Stack)中. 故在這種狀態下可以查看函數的變量值等各種屬性. 但在函數處於”停止”狀態之後, “棧”就會自動撤銷, 它也就無法查看各種信息了

關於Gdb的更多命令, 你可以在啓用Gdb後, 輸入help命令查看.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章