gdb中namespace的问题

 

gdb 中namespace的问题
 
    由于 namespace能防止命名冲突,因此在许多工程中会使用namespace。但是gdb
调试的时候如果需要强制将 void*指针转化成namespace中的某个struct或者class时,
会出现一些问题。下面通过举例介绍解决的方法。
 
    测试代码如下所示,总共两个文件,在 test.h中使用了namespace,并在其中定
义了一个 structclassstruct类似)。在test.cpp中展示了两种使用namespace
方法,并定义了一个 void * 的指针该指针指向namespace结构定义的一个变量,主
要展示如何在 gdb中察看该void*指针的内容。主要使用了gcc 3.2.2和gcc 3.4.3两个
编译器(分别对应 redhat 9.0和redhat AS4)。
 
/****************************
 test.h
*****************************/
ifndef __TEST_H__
#define __TEST_H__
 
namespace MYNAMESPACE
{
        int iTest;
        struct TTest
        {
                int     _iVal;
                char _cVal;
        };
}
 
#endif
 
 
/****************************
 test.cpp
*****************************/
#include <iostream>
#include "test.h"
 
using namespace std;
 
int main()
{
        /* way 1
        using namespace MYNAMESPACE;
        iTest = 10;
        TTest stTest = {10, 'a'};
 
        int * pi = &iTest;
        TTest * pt = &stTest;
        */
 
      
        // way 2
         MYNAMESPACE::iTest = 10;
        MYNAMESPACE::TTest stTest = {10, 'a'};
 
        int * pi = & MYNAMESPACE::iTest;
        MYNAMESPACE::TTest * pt = &stTest;
       
 
        void * pv = &stTest;   //target: get the value of pv in gdb
 
        cout << "pi = " << *pi << endl;
        cout << "pt->_iVal = " << pt->_iVal << endl;
        cout << "pt->_cVal = " << pt->_cVal << endl;
 
        return 0;
}
 
 
上述两种使用 usespace的方式得到的结果均如下:
///
//gcc 3.2.2
///
(gdb) p pi
$1 = ( int *) 0x8049bac
(gdb) p pt
$2 = (TTest *) 0xbffff550
 
///
//gcc 3.4.3
///
(gdb) p pi
$1 = ( int *) 0x8049db8
(gdb) p pt
$2 = (MYNAMESPACE::TTest *) 0xbfeeb840
 
    由上述结果可以看出 gcc 3.2.2下识别pt是TTest *类型,因此获得pv的
值可以强制转化成 TTest*即可,如下所示:
(gdb) p *(TTest*)pv
$3 = {_iVal = 10, _cVal = 97 'a'}
(gdb) p ((TTest*)pv)->_iVal
$4 = 10
(gdb) p ((TTest*)pv)->_cVal
$5 = 97 'a'
 
   但是在 gcc 3.4.3中pt却被识别成MYNAMESPACE::TTest *类型,而像上面
一样使用强制转化却出现问题:
(gdb) p *(MYNAMESPACE::TTest*)pv
A syntax error in expression, near `)pv'.
   因此需要强制表示该符号类型,如下所示:
(gdb) p *('MYNAMESPACE::TTest' *)pv
$3 = {_iVal = 10, _cVal = 97 'a'}
(gdb) p (*('MYNAMESPACE::TTest' *)pv)->_iVal
$4 = 10
(gdb) p (*('MYNAMESPACE::TTest' *)pv)->_cVal
$5 = 97 'a'
   即要使用符号''来强制说明一下,否则 gcc会不认识该符号。另外如果在
gcc 3.2.2中使用 p *('MYNAMESPACE::TTest' *)pv,则会报错:
   No symbol "MYNAMESPACE" in current context.
 
   因此, namespace在不同的编译器中处理是不一样的,主要还是用p命令来
察看其具体被识别成什么类型,然后使用强制转化即可,注意的是如果被识
别成 MYNAMESPACE::**时,使用强制转化时需要使用符号''来强制转化。当然
内存地址转化也同样如此。
 
### GNU Debugger (GDB) 使用教程 #### 编译带有调试信息的源码 为了能够利用 GDB 对 C/C++ 程序进行有效的调试,在编译阶段应当加入 `-g` 参数来包含必要的调试数据。例如对于名为 `a.cpp` 的文件,可以执行如下命令完成编译工作: ```bash g++ a.cpp -o a -g ``` 这一步骤确保生成的目标文件包含了完整的符号表以及行号映射等辅助信息,有助于后续更精确地追踪代码逻辑[^1]。 #### 启动 GDB 并加载可执行文件 一旦拥有了带调试信息的二进制文件(假设为 `a.out`),就可以通过指定此文件名启动 GDB 了;在 Windows 下则是对应的 `.exe` 文件。具体做法是在终端输入相应的指令: - **Linux**: `gdb ./a.out` - **Windows**: `gdb a.exe` 此时即进入了交互式的 GDB 控制台界面,准备就绪等待进一步的操作指示。 #### 掌握基本控制流管理命令 熟悉几个核心的断点设置与流程控制语句是高效运用 GDB 的基础之一。下面列举了一些常用的选项及其缩写形式: - 设置断点 (`break`) 或简写成 `b`:允许用户定义特定位置暂停程序运行以便检查状态; - 继续执行直到下一个断点 (`continue`) 或简记作 `c`:让被中断的应用继续前进直至再次触发其他已设好的停止条件为止; - 单步跟踪函数内部细节 (`step`) 或简称 `s`:逐条分析当前所在方法内的每一条语句的行为模式而不跳过任何一层嵌套调用关系; - 步过顶层调用 (`next`) 或写作 `n`:同上一项目相似之处在于也是按顺序推进单个表达式解析过程,区别仅限于当遇到子程序入口时不深入探究而是直接越过返回至上层环境继续前行; - 查看变量值 (`print <variable_name>`) 或简化版 `p <variable_name>`:即时获取某项局部或全局实体的具体数值表现情况。 以上这些功能极大地增强了开发者排查错误的能力并促进了对复杂算法实现机制背后原理的认知水平提升[^2]。 #### 实际案例演练——简单C++程序调试示范 考虑这样一个简单的例子,其中存在潜在缺陷待我们借助 GDB 发现它的确切原因所在: ```cpp #include <iostream> using namespace std; int main() { int num; cout << "Enter an integer: "; cin >> num; if(num % 0 == 0){ // 错误发生在这一行,除数不能为零. cout<<"The number is even."<<endl; }else{ cout<<"The number is odd."<<endl; } } ``` 针对上述代码片段可能引发崩溃的情况,可以在 GDB 中采取以下措施来进行诊断: 1. 创建一个新的 CPP 源文件并将上面的内容复制进去保存好。 2. 执行前面提到过的编译加调试信息保留操作。 3. 开启 GDB 加载刚刚得到的结果文件。 4. 利用 `list` 命令查看源代码列表找到可疑区域附近的位置编号。 5. 应用 `breakpoint` 来标记出想要重点观察的地方比如第7行处。 6. 输入 `run` 让应用程序开始运行,并按照提示提供测试用的数据。 7. 当达到预置的停靠站点之后,尝试打印相关联的关键参数看看是否有异常状况发生。 8. 如果发现确实存在问题,则依据实际情况调整策略重复之前的步骤直至彻底解决问题根源。 这种实战练习不仅加深了理论知识的记忆程度同时也提高了动手能力和解决实际问题的信心。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值