用gdb调C++标准库

简介:

我一直都是在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 --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容器的支持是极好的:


(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) 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中的内容:


(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 里定义的。我们打开这个文件看一下。


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

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


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入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
1月前
|
存储 C++ 容器
C++STL(标准模板库)处理学习应用案例
【4月更文挑战第8天】使用C++ STL,通过`std:vector`存储整数数组 `{5, 3, 1, 4, 2}`,然后利用`std::sort`进行排序,输出排序后序列:`std:vector<int> numbers; numbers = {5, 3, 1, 4, 2}; std:sort(numbers.begin(), numbers.end()); for (int number : numbers) { std::cout << number << " "; }`
21 2
|
2月前
|
存储 算法 安全
深入理解C++中的std::chrono库:持续时间的比较与应用
深入理解C++中的std::chrono库:持续时间的比较与应用
54 1
|
2月前
|
算法 数据处理 C++
【C++ 20 新特性 算法和迭代器库的扩展和泛化 Ranges】深入浅出C++ Ranges库 (Exploring the C++ Ranges Library)
【C++ 20 新特性 算法和迭代器库的扩展和泛化 Ranges】深入浅出C++ Ranges库 (Exploring the C++ Ranges Library)
111 1
|
17小时前
|
机器学习/深度学习 JSON 编译器
C++ 资源大全:标准库、Web框架、人工智能等 | 最全整理
C++ 资源列表,内容包括: 标准库、Web应用框架、人工智能、数据库、图片处理、机器学习、日志、代码分析等
8 1
|
6天前
|
JSON Java Linux
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
20 2
|
6天前
|
存储 安全 算法
【C++入门到精通】 原子性操作库(atomic) C++11 [ C++入门 ]
【C++入门到精通】 原子性操作库(atomic) C++11 [ C++入门 ]
14 1
|
6天前
|
算法 安全 调度
【C++入门到精通】 线程库 | thread类 C++11 [ C++入门 ]
【C++入门到精通】 线程库 | thread类 C++11 [ C++入门 ]
15 1
|
13天前
|
存储 算法 C++
详解C++中的STL(标准模板库)容器
【4月更文挑战第30天】C++ STL容器包括序列容器(如`vector`、`list`、`deque`、`forward_list`、`array`和`string`)、关联容器(如`set`、`multiset`、`map`和`multimap`)和容器适配器(如`stack`、`queue`和`priority_queue`)。它们为动态数组、链表、栈、队列、集合和映射等数据结构提供了高效实现。选择合适的容器类型可优化性能,满足不同编程需求。
|
20天前
|
存储 算法 程序员
C++从入门到精通:2.2.1标准库与STL容器算法深度解析
C++从入门到精通:2.2.1标准库与STL容器算法深度解析
|
26天前
|
C语言 C++ Windows
标准库中的string类(下)——“C++”
标准库中的string类(下)——“C++”