您的位置:首页 > 其它

调试的艺术

2016-01-16 22:50 399 查看
调试的本质:确认原则。确认你认为正确的事情确实是正确的。

调试的其他原则:

从简单工作开始调试。

使用自顶向下方法。

使用调试工具确定段错误的位置。

通过发出中断确定无限循环的位置。

使用二分搜索。

调试器暂停的代码行,实际上是将要执行的代码行。
断点类型:断点 监视点 捕获点

设置断点的方式:

break function 在函数function()入口处(第一行可执行代码)设置断点。

break line_number 在当前活动源文件的line_number处设置断点。对于多行程序,这要么是上次使用list命令查看其内容的文件,要么是包含main()的文件。

break filename:line_number 如果filename不在当前工作目录中,则可以给出相对路径名或者完整路径名

break filename:function 重载函数或者使用同名静态函数的程序可能需要这种形式。

tbreak是设置临时断点,在第一次中断之后会自动删除。

删除、禁用断点的方式:

delete breakpoint_list 删除断点使用数字标识符

delete 删除所有断点

clear 清除gdb将执行的下一个指令处的断点。

clear function、clear filename:function、clear line_number、clear filename:line_number

disable breakpoint_list

enable breakpoint_list

查看断点属性:info breakpoints

标识符(Num):断点的唯一标识符。

类型(Type):断点的类型。

部署(Disp):下次到达断点后,断点上会发生什么事情。有3种,保持(keep),删除(del),禁用(dis)

启用状态(Enb):启用还是禁用。

地址(Address):这是内存中设置断点的位置。

位置(What):断点所在位置的行号和文件名。

另外还可以查看,断点已经到达多少次。

恢复执行:

step与next单步调试,后面可以接受一个整数参数n,表示执行n行代码。 根据自顶向下调试原则,应该首先使用next

continue恢复程序执行,后面可以接受一个整数参数n,表示gdb忽略下面n个断点。

finish 当单步进入函数,想要跳过函数的剩余部分,可以使用finish。

until 执行程序,直到它到达内存地址比当前内存地址更高的机器指令,而不是直到到达源代码中一个更大的行号。但是until确实能够,跳过循环体,到达循环体外的下一行代码。

事实上,until可以接受源代码中的位置作为参数,就像break一样。这样就可以在任何想要暂停的位置暂停程序了。

eg:until 17,until swap, until swapflaw.c:17, until swapflaw.c:swap

条件断点:

break break-args if (condition) 其中break-args是可以传递给break以指定断点位置的任何参数。condition是布尔表达式,括号是可选的。

eg:break 180 if i < 0 && pt == NULL,break myfunc if i % (j + 3) != 0,break test.c:44 if strlen(mystring) == 0

如果在gdb中使用库函数,而该库不是调试符号编译的,那么唯一能在断点条件中使用的返回值类型为int。

可以对正常断点设置条件以将它们转化为条件断点,使用condition break-num expression,取消条件则是condition break-num

断点命令列表:

为了实现遇到一个断点之后,自动执行一些gdb命令,可以使用断点命令列表。

commands breakpoint-num

commands

end

breakpoint-num是断点标示符,下一行的commands是任意的命令,end标示输入完毕。

eg:break fibonacci

commands 1

>silent 为了使gdb更安静地触发断点,必须是第一个命令

>printf "fibonacci was passed %d.\n", n gdb的输出命令,与c语言的语法相同

>continue 断点之后继续自动执行

>end

可以将固定命令列表定义为宏,show user可以得到所有宏的列表

define print_and_go

>printf $arg0, $arg1 最多拥有10个参数

>continue

>end

commands 1

>silent

>print_and_go "fibonacci was passed %d\n" n 注意参数没有逗号

>end

gdb可以调用源代码中的函数:

call myfunc()

在断点命令列表中使用,可以避免修改源码,这点很强大,很方便。

监视点:

它没有住在某一行源代码中,而是当表达式改变时,暂停程序执行。监视的变量必须存在且正处在作用域中,否则无法设置监视点,出作用域之后,监视点也会自动删除。

watch var

watch expression

复杂数据类型变量查看:

动态数组 int* x = (int*)malloc(25 * sizeof(int)); 格式为:p *x@25 也可以用强制转换 p (int[25]) *x

结构体 struct node { int val; struct node* left; struct node* right; }; struct node* nsp; 格式为: p *nsp

类 class node { public: static class node* root; int val; class node* left; class node* right; node(int x); static void insert(int x); static void printtree(class node* nptr); }; class node::root = 0; class node* nsp; 格式为: p *nsp

使用ptype可以查看结构体或类的结构,ptype node。

程序崩溃:用编程界的行话说,当某个错误导致程序突然和异常地停止执行时,程序崩溃。

迄今最常见的导致程序崩溃的原因是试图在未经允许的情况下访问一个内存单元。硬件会感知这件事,并执行对操作系统的跳转。在unix系列的平台上,操作系统一般会宣布程序导致段错误(seg fault),并停止程序的执行。在windows系统上,对应的术语是一般保护错误(general protection fault)。使用调试器可以记录崩溃调用栈。

核心文件的使用:

gdb -c core.num target

core.num 是崩溃生成的文件 target是执行的程序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息