標籤:
我一直都是在Linux下做開發的,但是我對GDB的使用並不多。因為平都是用QtCreator偵錯工具的。因為工作的原因,以後可能不能再依賴QtCreator了。於是我好好研究一下~
之前為什麼沒有深入使用GDB,QtCreator帶來一定的便利是一方面,另一方面是覺得GDB遇到了vector, map, set, list就沒辦法看資料了。
今天我研究了一下,其實也是Easy的。
範例程式碼:
#include <iostream>#include <string>#include <vector>#include <map>using namespace std;int main(){ int i1 = 32; int i2 = 45; double d = i1 + i2 / 3; vector<string> vstr; vstr.push_back("Hello"); vstr.push_back("World"); vstr.push_back("!"); map<string, int> m_si; m_si["A"] = 12; m_si["D"] = 93; m_si["B"] = 77; return 0;}
編譯的時候:
$ g++ -o test-gdb test-gdb.cpp -g
在GDB調試中,可以用print指令查看變數或常量的值。
可能是我本機所安裝的GDB版本較高的緣故,原生GDB本謝就很支援STL中的容器。如下是我GDB的版本資訊:
$ gdb --versionGNU gdb (GDB) Red Hat Enterprise Linux (7.2-75.el6)Copyright (C) 2010 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 "i686-redhat-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.
對STL容器的支援是極好的:
(gdb) p vstr$1 = std::vector of length 3, capacity 4 = {"Hello", "World", "!"}(gdb) p m_si$2 = std::map with 3 elements = { ["A"] = 12, ["B"] = 77, ["D"] = 93}
能看到這樣的資訊其實已經很不錯了。
但是我公司系統的GDB可沒這麼智能。列印一下vector,就會蹦出好大堆資訊。如果是map的話,那就更嚇人了。
<此處展示可怕的提示資訊>
其實,在這大堆資訊裡面只有小部分是我們關注的。GDB很靈活,我們可以在裡面自訂函數。我可以在GDB裡定義一個函數從vector裡提取重要的資訊進行顯示。
從 這裡 下載一個stl-views.gdb檔案。在這個文裡定義了很多緒如:pvector, pmap, pstring之類的GDB函數供我們使用。
將這個檔案下載到HOME目錄,然後:
$ cat stl-views-1.0.3.gdb >> .gdbinit
這樣,每次啟動 gdb的時候,都會自動載入 ~/.gdbinit 檔案中的內容。
13 vector<string> vstr;(gdb) n14 vstr.push_back("Hello");(gdb) n15 vstr.push_back("World");(gdb) n16 vstr.push_back("!");(gdb) p<TAB><TAB>passcount plist_member print pstring pythonpath pmap print-object ptype pbitset pmap_member printf pvector pdequeue ppqueue pset pwd plist pqueue pstack pwstring
輸入了p之後,每次連續按兩次TAB鍵都會列出以p開頭的命令。這裡我們看到了:pstring, pvector, pwstring, pstack, pmap, pmap_member等等。
我們用一下pvector來查看vstr中的內容:
(gdb) pvector vstrelem[0]: $3 = "Hello"elem[1]: $4 = "World"elem[2]: $5 = "!"Vector size = 3Vector capacity = 4Element type = std::basic_string<char, std::char_traits<char>, std::allocator<char> > *
這個命令果然列印出了很多有價值的資訊。
博主有個習慣,我不僅要知其然,我還要知其所以然。於是我研究了一下 .gdbinit檔案裡的內容。這個函數都是在 ~/.gdbinit 裡定義的。我們開啟這個檔案看一下。
define pvector if $argc == 0 help pvector else set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start set $capacity = $arg0._M_impl._M_end_of_storage - $arg0._M_impl._M_start set $size_max = $size - 1 end if $argc == 1 set $i = 0 while $i < $size printf "elem[%u]: ", $i p *($arg0._M_impl._M_start + $i) set $i++ end end if $argc == 2 set $idx = $arg1 if $idx < 0 || $idx > $size_max printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max else printf "elem[%u]: ", $idx p *($arg0._M_impl._M_start + $idx) end end if $argc == 3 set $start_idx = $arg1 set $stop_idx = $arg2 if $start_idx > $stop_idx set $tmp_idx = $start_idx set $start_idx = $stop_idx set $stop_idx = $tmp_idx end if $start_idx < 0 || $stop_idx < 0 || $start_idx > $size_max || $stop_idx > $size_max printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max else set $i = $start_idx while $i <= $stop_idx printf "elem[%u]: ", $i p *($arg0._M_impl._M_start + $i) set $i++ end end end if $argc > 0 printf "Vector size = %u\n", $size printf "Vector capacity = %u\n", $capacity printf "Element " whatis $arg0._M_impl._M_start endenddocument pvector Prints std::vector<T> information. Syntax: pvector <vector> <idx1> <idx2> Note: idx, idx1 and idx2 must be in acceptable range [0..<vector>.size()-1]. Examples: pvector v - Prints vector content, size, capacity and T typedef pvector v 0 - Prints element[idx] from vector pvector v 1 2 - Prints elements in range [idx1..idx2] from vectorend
看全部有點多,我們暫且不看多個參數的那部分,我們分析一下只有一個參數的一部分:
define pvector if $argc == 0 # 如果沒有帶參數,那麼就列印協助提示資訊 help pvector else # 如果有參數,那麼接下來準備一下size, capacity, size_max 這三個重要的參數。 set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start # arg0 就是第一個參數,也就是vstr數組對象。注重 size 是怎麼計算的。 set $capacity = $arg0._M_impl._M_end_of_storage - $arg0._M_impl._M_start set $size_max = $size - 1 end if $argc == 1 # 如果只有一個參數,說明要求列印出vector中所有的元素 set $i = 0 while $i < $size # 用一個 while 迴圈,用printf與p,列印出列表中的所有元素 printf "elem[%u]: ", $i p *($arg0._M_impl._M_start + $i) # 注意看哦!!!! set $i++ end end
所有的說明都寫在上面的注釋中了,自己去悟吧!
如果print命令能像C++裡的模板函數那可以對特定類型進行“偏特化”就好了。上面是有個問題的:
在“p *($arg0._M_impl._M_start + $i)”這行命令中,如果vector的成員還是個STL的容器該怎麼辦?這是個問題~
用gdb調C++標準庫