gdb调试技术3

    技术2026-09-28  4

    本文首先以一个二叉树插入算法的实现作为例子说明GDB查看程序数据的相关方法,代码如下:

    1: // bintree.c: routines to do insert and sorted print of a binary tree 2: 3: #include 4: #include 5: 6: struct node { 7: int val; // stored value 8: struct node *left; // ptr to smaller child 9: struct node *right; // ptr to larger child 10: }; 11: 12: typedef struct node *nsp; 13: 14: nsp root; 15: 16: nsp makenode(int x) 17: { 18: nsp tmp; 19: 20: tmp = (nsp) malloc(sizeof (struct node)); 21: tmp->val = x; 22: tmp->left = tmp->right = 0; 23: return tmp; 24: } 25: 26: void insert(nsp *btp, int x) 27: { 28: nsp tmp = *btp; 29: 30: if (*btp == 0) { 31: *btp = makenode(x); 32: return ; 33: } 34: 35: while (1) 36: { 37: if (x < tmp->val) { 38: 39: if (tmp->left != 0) { 40: tmp = tmp->left; 41: } else { 42: tmp->left = makenode(x); 43: break ; 44: } 45: 46: } else { 47: 48: if (tmp->right != 0) { 49: tmp = tmp->right; 50: } else { 51: tmp->right = makenode(x); 52: break ; 53: } 54: 55: } 56: } 57: } 58: 59: 60: void printtree(nsp bt) 61: { 62: if (bt == 0) return ; 63: printtree(bt->left); 64: printf("%d/n ",bt->val); 65: printtree(bt->right); 66: } 67: 68: 69: int main(int argc, char *argv[]) 70: { 71: root = 0; 72: for (int i = 1; i < argc; i++) 73: insert(&root, atoi(argv[i])); 74: printtree(root); 75: }

    在调试这个二叉树插入程序的时候,我们会非常关心insert方法的执行情况,在进入那个while(1)循环后,我们可能会做以下的操作:

    (gdb) p tmp->val $1=12 (gdb) p tmp->left $2 = (struct node *) 0x8049698 (gdb) p tmp->right $3 = (struct node *) 0x0

    这个操作显得累赘又麻烦,我们可以有以下的改进措施:

    1.直接打印结构体tmp :

    (gdb) p *tmp $4 = {val = 12, left = 0x8049698, right = 0x0}

    2.使用display命令 :我们在#37设置断点,然后运行程序,待程序运行至该断点停下后使用 display = disp 命令对某一个变量进行监视(之所以这样做是因为这个变量必须存在在该栈帧上,也就是说调试的时候这个变量的确被创建并且没有被销毁),程序以后只要一停止 就打印这个变量的值在屏幕上:

    (gdb) disp *tmp 1: *tmp = {val = 12, left = 0x8049698, right = 0x0} (gdb) c Continuing. Breakpoint 1, insert (btp=0x804967c, x=5) at bintree.c:37 37 if (x < tmp->val) { 1: *tmp = {val = 8, left = 0x0, right = 0x0}

    也可以使用dis disp 1使这个监视动作失效(enable disp 1则恢复),undisp 1为删除。info display为查看当前所有自动打印点相关的信息

    3.使用命令列表 :在上篇 中已经叙述,在此不再赘述。

    4.使用call命令: 我们在代码中已经有了一个打印整个树的函数printtree,使用call命令我们可以直接利用代码中的方法进行变量监视,在每次insert完成的时候调用printtree对二叉树进行打印:

    (gdb) commands 2 Type commands for when breakpoint 2 is hit, one per line. End with a line saying just "end". >printf "*********** current tree ***********" >call printtree(root) >end

    5.使用DDD的Data Window图形化表示 :单击右键在root这个变量上然后选择display *root,每次在#37行停下时,在Data Window内对整个树的都有图形化表示,在左右子树上,你可以使用右键单击然后选择Display *()来显示。(Tips:你可以以--separate参数启动DDD,这样每个Window都是独立的,你可以获得更大的视野)。

    补充:

    1.打印数组: p *pointer@number_of_elements ,其中number_of_elements表示显示pointer这个变量中的几个成员。另外一种方式是类型转换,例如下列程序:

    1: int *x; 2: main() 3: { 4: x = (int *) malloc(25*sizeof (int )); 5: x[3] = 12; 6: }

    除了可以使用:

    (gdb) p *x@25 $1 = {0, 0, 0, 12, 0 }

    我们还可以使用:

    (gdb) p (int [25]) *x $2 = {0, 0, 0, 12, 0 }

    2.打印本地变量 :info locals,会打印当前栈帧的本地变量。

    3.以不同形式打印变量 :p/paramenters variable  parameters 可以是 x 表示打印变量以十六进制表示,f为浮点,c为character,s为string。

    4.打印历史查看过的变量:使用$number,而只使用$表示上一个变量。

    (gdb) p tmp->left $1 = (struct node *) 0x80496a8 (gdb) p *(tmp->left) $2 = {val = 5, left = 0x0, right = 0x0} (gdb) p *$1 $3 = {val = 5, left = 0x0, right = 0x0}

    (gdb) p tmp->left $1 = (struct node *) 0x80496a8 (gdb) p *$ $2 = {val = 5, left = 0x0, right = 0x0}

    5.修改被调试程序运行时的变量值 :set x = 12。

    6.利用自定义变量方便调试:例如,

    1: int w[4] = {12,5,8,29}; 2: main() 3: { 4: w[2] = 88; 5: }

    我们设置i,然后利用这个变量对这个数组进行遍历:

    (gdb) set $i = 0 (gdb) p w[$i++] $1=12 (gdb) $2=5 (gdb) $3=88 (gdb) $4=29

    7.强制类型打印

    p {type}address:把address指定的内存解释为type类型(类似于强制转型,更加强)

    8.设置一些常见选项

    1) set print array:打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。默认关闭2) set print elements num-of-elements:设置GDB打印数据时显示元素的个数,缺省为200,设为0表示不限制(unlimited)3) set print null-stop:设置GDB打印字符数组的时候,遇到NULL时停止,缺省是关闭的 4) set print pretty:设置GDB打印结构的时候,每行一个成员,并且有相应的缩进,缺省是关闭的5) set print object:设置GDB打印多态类型的时候,打印实际的类型,缺省为关闭6) set print static-members:设置GDB打印结构的时候,是否打印static成员,缺省是打开的7) set print vtbl:GDB将用比较规整的格式来显示虚函数表,缺省是关闭的

    参考文献: 《Art of Debugging》 《Linux® Debugging and Performance Tuning: Tips and Techniques》

    Author:gnuhpc WebSite:blog.csdn.net/gnuhpc

    最新回复(0)