1、命令+条件中断和监视点的使用
1.1 监视点
监视点是指示GDB每当某个表达式改变了只,就暂停执行指令。如watch i它会使得每当i改变值时GDB就暂停。也可以使得watch后面的更复杂如:watch (I | j > (2) && I > 24) && strlen(name)> 6这是将监视点看作“附加”在表达式上,当表达式的值改变时,GDB会暂停程序的执行。
1.2 监视点和断点的区别
断点与源代码中的一个位置关联,监视点则是对与内存,当变量不存在时,GDB自动删除监视点。
1.3 使用监视点
监视点的使用形式如watch var,GDB实际上在var的内存位置改变值时中断。
1.4 监视点的使用场景
监视点使用的最多的地方是对于指针的监视,对于C、C++这样的指针型语言,可能对指针进行修改,这是时候watch可以有效的监视指针。形如:p =&y; p = &x监视y可以知道值是在何处被修改的,防止不必要的错误。
1.5 结构体的输出
对于C这样的语言,在工程中少不了使用结构体,但是我们在GDB调试的时候每次都比较麻烦,为了打印结构体里面的变量,我们要重复的输入ptempstruct->value的表达式。不过还好有简单的方法如下。
1、 print *tmp:tmp是指针结构,tmp指向结构体,因此*tmp是这个结构体本身,这样能输出结构体的所有变量。
2、 使用GDB的display命令:如果知道会在每次遇到断点时键入这个命令,那么使用GDB的display命令(简写disp),这个命令要求GDB在执行中每次有暂停(由于有断点,使用next、step命令等)时就输出指定条目。
3、 使用GDB的commands命令,在给定点上时查看子结点的值。下面是对数据结构中的二叉树的输出。
commands 1
p tmp->val
if (tmp->left != 0)
ptmp->left->val;
else
printf“%s\n” “none”
end
if (tmp ->right != 0)
ptmp->right->val;
else
printf“%s\n” “none”
end
end
4、 使用GDB的call,可以对现有代码进行调用函数,调试中的一个常见方法是隔离出现问题的第一个数据项。在上下文中,可以通过每次完成对insert的调用时输出整个树来完成这件事情。
command 2
printf “*******current tree *********”
call printtree(root) printtree是我们自己写的函数
end
DDD中可以使用ddd –separate bintree来分离窗口,为了使调试更为方便和直观。
2、 动态数组的检查
在编程中我们常常会使用动态数组,例如:
int x[25];
print x
int *x;
x = (int *)malloc(25 * sizeof(int));
p x 这时只会打印x[0]的值。怎样才能输出x数组中的所有值呢?
解决方法:在GDB中,可以通过创建一个人工数组(artificial array)来解决这个问题。如:
int *x;
main()
{
x = (int*)malloc(25 * sizeof(int));
x[3] = 12;
}
可以使用p *[email protected]可以将动态数组里面的数据全部打印出来。
人工数组的形式:*[email protected],GDB还允许在适当的时候使用类型强制转换,比如:p (int[25])*x进行打印。
3、 C++中对象的调试
对于C++来说,如果使用了对象来建立二叉树则在node中不能使用p *root来打印,这是会报错:can notaccess memory at address,用print打印也得换一种形式如p *node::root这样才能打印出来,因为root是class node的对象。