gdb调试c++的STL容器



我一直都是在Linux下做开发的,但是我对GDB的使用并不多。因为平都是用QtCreator调试程序的。因为工作的原因,以后可能不能再依赖QtCreator了。于是我好好研究一下~

之前为什么没有深入使用GDB,QtCreator带来一定的便利是一方面,另一方面是觉得GDB遇到了vector, map, set, list就没办法看数据了。

今天我研究了一下,其实也是Easy的。

示例代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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;
}

编译的时候:

?
1
$ g++ -o test-gdb  test-gdb.cpp -g

在GDB调试中,可以用print指令查看变量或常量的值。

可能是我本机所安装的GDB版本较高的缘故,本机的GDB本谢就很支持STL中的容器。如下是我GDB的版本信息:

?
1
2
3
4
5
6
7
8
9
10
gdb  --version
GNU 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容器的支持是极好的:

?
1
2
3
4
5
6
7
8
9
(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目录,然后:

?
1
cat  stl-views-1.0.3.gdb  >> ~/.gdbinit

这样,每次启动 gdb的时候,都会自动加载 ~/.gdbinit 文件中的内容。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
13        vector<string> vstr;
(gdb) n
14        vstr.push_back("Hello");
(gdb) n
15        vstr.push_back("World");
(gdb) n
16        vstr.push_back("!");
(gdb) p<TAB><TAB>
passcount     plist_member  print         pstring       python
path          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中的内容:

?
1
2
3
4
5
6
7
(gdb) pvector vstr
elem[0]: $3 = "Hello"
elem[1]: $4 = "World"
elem[2]: $5 = "!"
Vector size = 3
Vector capacity = 4
Element type  = std::basic_string<char, std::char_traits<char>, std::allocator<char> > *

这个命令果然打印出了很多有价值的信息。

博主有个习惯,我不仅要知其然,我还要知其所以然。于是我研究了一下 .gdbinit文件里的内容。这个函数都是在 ~/.gdbinit 里定义的。我们打开这个文件看一下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
    end
end
 
document 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 vector
end

看全部有点多,我们暂且不看多个参数的那部分,我们分析一下只有一个参数的一部分:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

所有的说明都写在上面的注释中了,自己去悟吧!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值