用gdb調C++標準庫

來源:互聯網
上載者:User

標籤:

我一直都是在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++標準庫

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.