每天学点GDB 8

本文介绍如何使用GDB调试工具遍历C++ STL map容器中的元素,包括获取内存地址和使用自动化脚本简化调试过程。

使用GDB来进行STL容器的调试

现代C++中STL使用的越来越普遍,较之其它类型,stl容器类的调试显得复杂度更好。本篇以map为例说明如何利用gdb来遍历map中的各成员变量。

源码如下

#include <map>
#include <iostream>
#include <string>

using namespace std;

int main(int arg, char** argv) {
  map<int, string> mapExample;
  mapExample.insert(pair<int,string>(1,"demo_one"));
  mapExample.insert(pair<int,string>(2,"demo_two"));
  mapExample.insert(pair<int,string>(3,"demo_three"));
  map<int,string>::iterator iter;
  for ( iter = mapExample.begin();iter!=mapExample.end();iter++) {
    cout<<iter->second<<endl;
  }
  return 0;
}

编译运行

g++ -o demo -g stl_test.cpp

运行

gdb ./demo
br 14
r

显示mapExample容器中的各个元素

p mapExample
$1 = std::map with 3 elements = {[1] = "demo_one", [2] = "demo_two", [3] = "demo_three"}

如果想要知道每个element的所在的内存区域,需要先得到stl map的类型。

ptype mapExample

显示如下,成员函数部分略去

type = class std::map<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<int>, std::allocator<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > [with _Key = int, 
         _Tp = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Compare = std::less<int>, 
         _Alloc = std::allocator<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >] {
  private:
    _Rep_type _M_t;

至此关键性成员变量显示即_M_t

顺着这条思路继续往下,查看_M_t的结构定义

p mapExample._M_t

结果显示出stl map实现使用了红黑二叉树rb-tree

  _M_impl = {
    <std::allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {
      <__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<No data fields>}, <No data fields>}, 
    members of std::_Rb_tree<int, std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::_Select1st<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::less<int>, std::allocator<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_Rb_tree_impl<std::less<int>, false>: 
    _M_key_compare = {
      <std::binary_function<int, int, bool>> = {<No data fields>}, <No data fields>}, 
    _M_header = {
      _M_color = std::_S_red, 
      _M_parent = 0x6040b0, 
      _M_left = 0x604040, 
      _M_right = 0x604120
    }, 
    _M_node_count = 3
  }
}

至此,事情变的简单了,利用_M_left和_M_right就可以遍历各个二叉树结点了。

手工方式作一次不会觉着很累,但次次都手工查看会觉着不厌其烦。幸运的是,早有人已经提供了自动化的脚本。具体链接如下

https://gist.github.com/skyscribe/3978082

使用方法是将上述链接中的内容保存到~/.gdbinit中,如果没有.gdbinit就手工创建一个,该文件在gdb每次启动时会被最先读入。

有了上述脚本,就可以用plist, pmap, pvector来遍历stl容器了。

 

 

<think>好的,我现在需要帮助用户确定每天应该花多少时间学习之前提到的UNIX环境高级编程的基础知识。用户已经得到了一个详细的学习路线,现在他们想知道每天应该投入多少时间。 首先,我需要回顾用户之前的提问历史。用户最初询问了学习APUE前需要哪些基础知识,现在跟进询问学习时间安排。这说明用户可能已经开始规划学习,并希望有一个明确的时间管理策略。 用户可能的情况是,他们可能是学生、自学者或转行人士,希望通过系统学习进入系统编程领域。他们可能已经有部分基础,但需要巩固,或者完全是新手。用户的需求是高效学习,同时平衡其他生活或工作责任,所以需要具体的时间建议。 接下来,我需要分析用户的具体问题:每天学习多长时间合适?这可能涉及到学习效率、内容分解、避免疲劳等因素。用户可能希望一个可持续的计划,而不是短期的强度过高的安排。 在之前的回复中,我分阶段推荐了不同的学习内容,现在需要将这些阶段分解到每日学习中。例如,用户可能需要知道每个阶段需要多少周,每天多少小时,以及如何分配理论学习实践时间。 需要考虑的因素包括:总学习时间(2-3个月)、不同阶段的时间分配(基础期、进阶期、实战期)、每日学习时间休息的平衡。此外,用户可能有不同的学习速度,所以建议要有一定的灵活性。 可能还需要提醒用户避免过度学习,防止疲劳,保持持续进步。例如,建议采用番茄工作法,每天分段学习,并强调实践的重要性,如每天写代码的时间比例。 还需要考虑不同学习者的背景。如果用户已经有C语言基础,可能基础期可以缩短;如果是新手,则需要更多时间。因此,可能需要给出一个范围,并建议用户根据自身情况调整。 最后,要确保建议具体可行,比如将每日时间分为理论学习和实践,每周安排复习时间,以及如何检测学习效果。同时,推荐一些时间管理工具或方法,帮助用户保持节奏。</think>根据学习目标和知识基础的不同,每日学习时长可参考以下分段方案(以零基础学习者为基准): --- ### 一、**时间分配原则** 1. **黄金比例**:理论(听课/读书)实践(写代码/操作命令)按 **1:2** 分配 (例如:1小时读书 → 配套2小时写代码) 2. **防遗忘机制**:每天用 **15分钟** 复习前日内容(如重画进程状态转换图) 3. **可持续性**:每周预留 **1天缓冲期** 用于补漏或休息 --- ### 二、**具体阶段规划** #### ▶ **阶段1:C语言强化(3-4周)** - **每日投入**:2-3小时 - 早间30分钟:精读《C和指针》重点章节(如指针数组关系) - 晚间90分钟:实现1个系统级代码(如用`malloc`模拟内存碎片化现象) - 周末加餐:用GDB调试复杂指针错误(如双重释放问题) #### ▶ **阶段2:操作系统理论(2-3周)** - **每日投入**:1.5小时理论 + 1小时实践 - 通过`fork()`创建多级子进程,用`pstree`观察进程树 - 用`mmap`实现进程间共享内存(对比`shmget`差异) - 推荐工具:`htop`实时观察内存变化 #### ▶ **阶段3:UNIX环境实战(4-6周)** - **每日投入**:3小时(侧重动手) - 早晨通勤:用手机SSH连接Linux服务器练习命令(如`lsof`分析文件描述符泄漏) - 深度实践:逐步实现简化版Shell(需处理信号、管道、重定向) - 典型案例:用`inotify`监控文件系统事件并触发自定义动作 --- ### 三、**高效学习策略** 1. **对抗碎片化** - 用`tmux`分屏同时打开:左侧写代码 → 右侧测试 → 下方`man`手册 - 禁止在多任务间切换(如学信号处理时专注`sigaction`结构体) 2. **记忆强化技巧** - 为每个系统调用创建速查卡片: $$ \text{卡片正面:open()功能} \\ \text{背面:O\_CREATO\_EXCL组合的原子性保证} $$ - 用`strace -f gcc hello.c`观察编译过程的系统调用链 3. **防疲劳建议** - 每45分钟用`watch -n 1 'cat /proc/loadavg'`监控系统负载(同步放松眼睛) - 高强度调试后,用`cmatrix`或`bastet`(俄罗斯方块终端版)短暂放松 --- ### 四、**进度自测表** | 学习周 | 达标标志 | 检测方法 | |--------|-------------------------------------|------------------------------| | 第2周 | 能手动解析ELF文件头 | 用`readelf -h /bin/ls`验证 | | 第4周 | 实现带信号处理的守护进程 | 通过`kill -SIGHUP`测试稳定性 | | 第6周 | 能解释`ls -l`输出的全部字段来源 | 对照`struct stat`成员逐一说明| --- ### 五、**灵活调整建议** - **加速方案**(有编程经验者): 每天追加1小时专题突破(如集中3天专攻`epoll`模型) - **减速方案**(遇核心难点时): 对多线程同步等复杂主题,可延长单日学习至4小时,但需搭配: ```c // 用Valgrind检测死锁示例 valgrind --tool=helgrind ./your_thread_program ``` --- 坚持6-8周后,你会自然产生"想用`poll()`优化IO"或"尝试修改文件权限掩码"的条件反射,此时即可顺畅进入《UNIX环境高级编程》的核心章节学习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值