实用调试技巧

  • 什么是bug?
  • 调试是什么?有多重要?
  • debug和release的介绍
  • windows环境调试介绍
  • 一些调试的实例
  • 如何写出好(易于调试)的代码
  • 编程常见的错误

1.什么是bug?

第一次被发现的导致计算机错误的飞蛾,也是第一个计算机程序错误。

后来把导致计算机出现问题的错误称之为bug

2.调试是什么?有多重要?

所有发生的事情都有一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心无愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤儿上,就是推理的途径

顺着这条途径顺流而下就是犯罪,逆流而上,就是真相

一名优秀的程序员是一名出色的侦探

每一次调试都是尝试破案的过程

拒绝迷信式调试!!!

2.1调试是什么?

调试,又称除错,是发现减少计算机程序或电子仪器设备中程序错误的一个过程。

调试的前提已经知道程序应该怎么执行,然后验证自己的想法,当前的程序是不是按照自己的想法在走

2.2调试的基本步骤?

  • 发现程序错误的存在
  • 以隔离、消除等方式对错误进行定位
  • 确定错误产生的原因
  • 提出纠正错误的解决办法
  • 对程序错误予以改正,重新测试

2.3Debug和Release的介绍

Debug通常称为调试版本,它包含调试信息,并且不做任何优化,便于程序员调试程序

Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用

 Debug版本是程序员用于寻找错误的版本

Release版本是用户使用的版本,没有调试信息

 3.windows环境调试介绍

3.1调试环境的准备

 在环境中选择debug选项,才能是代码正常调试

3.2学会快捷键

F5

启动调试,经常用来直接跳到下一个断点处

当程序中没有设置断点时,程序就会一步一步的往下走直到程序运行结束为止

此时的效果跟用CTRL+F5的效果是一样的

通常F5是和F9一起搭配使用

F9

创建断点和取消断点(按一下设置断点,再按一下取消断点)

断点的重要作用,可以在程序中的任意位置设置断点

这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去

下端代码中假设已经知道赋值是没有问题的,问题可能出现在打印处,所以在第15行处设置断点,按F5就能跳过前面的代码直接到断点处

 

 再按一次F5并不能跳到下一个断点处,按一下F5它会跑到逻辑上的下一个断点

取消断点,再按F5才能到下一个断点或者右击鼠标有一个禁用断点

 假设我们知道打印qian5次是没有问题,此时我们可以设置条件断点

此时为条件断点,只有当i==5时才会触发这个断点,按F5此时i就是5

F10

逐过程,通常用来处理一个过程可以是一次函数调用,或者是一条语句

F11

逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)

F10和F11在普通语句上是没有什么区别的,在函数调用上是有区别的

F11能够进入函数内部观察细节,而F10认为被调用的函数是一条语句,直接到下一条语句

CTRL+F5

开始执行不调试,如果想要程序直接运行而不调试就可以直接使用

3.3调试的时候查看程序当前信息

调试开始后,窗口中才能看到上面的选项

3.3.1.查看临时变量的值

 在监视中虽然是我们自己手动输入,但是我们想观察什么就观察,像自动窗口和局部变量这两个观察东西都不太方便

 想要看a中4个元素的内容写成a,4

3.3.2查看内存信息

3.3.3查看调用堆栈

代码之间进行互相调用,观察代码之间是如何相互调用的

查看调用堆栈,就很容易看出函数之间是如何调用的

 数据结构中的栈:

压栈

出栈

调用堆栈反映函数调用逻辑,在上面代码执行时,调用的函数依次放到栈区,释放时,从栈顶处先释放

栈是一种先进后出,后进先出的数据结构

在很多行代码中,函数之间的互相调用,直接浏览代码查看非常麻烦,借助调用堆栈就变得清晰明了

3.3.4查看汇编信息

在不同的编译器中汇编是不一样的,所以不会汇编没事,只需要知道当我们要找汇编信息时,我们应该在哪里找,分析一些简单的流程

出了在调试窗口中找反汇编,右击鼠标也能找到反汇编

3.3.5查看寄存器信息

像上面的eax、ebx就是寄存器

在调试窗口中能够找到寄存器,以及右击鼠标也能找到寄存器

4.多多动手,尝试调试,才能有进步

  • 一定要熟悉掌握调试技巧
  • 初学者可能80%的时间在写代码,20%的时间在调试,但是程序员可能20%的时间在写程序,但是80%的时间在调试
  • 这篇文章所写都是一些简单的调试,以后可能会出现很复杂调试场景;多线程程序的调试等
  • 多多使用快捷键,提升效率

5.一些调用实例

5.1 实例1:

计算3!=1+2+6=9,但是此时打印出15

这里我们就得找我们的问题

1.首先推测问题出现的原因。初步确定问题的原因

2.实际上手调试很有必要。

3.调试的时候我们心里有数

当我们调试的狮虎发现前两次的计算是正确的,但是第三次ret=12了,所以3的阶层算出来时15,也就是本来应该时6,但是现在x2了,也就是上一次的ret=2遗留下来,所以在每次使用ret之前都要重新等于1;

更改:

在第二个for循环之前加上一个ret=1;

5.2 实例2:

#include<stdio.h>
int main()
{
    int i=0;
    int arr[10]={0};
    for(i=0;i<=12;i++)
    {
        arr[i]=0;
        printf("hehe\n");
    }
    return 0;
}

 上面的代码陷入了死循环

经过调试我们发现当arr[12]的值被改为0的时候,i的值也被改为0,arr[12]的值在变的同时i的值也在变,通过&i和&arr[12]的地址我们发现它们共用同一块空间

 6.如何写出好(易于调试)

6.1 优秀的代码

1.代码运行正常

2.bug很少

3.效率高

4.可读性高

5.可维护性高

6.注释清晰

7.文档齐全

常见的coding技巧

1.使用assert

2.尽量使用const

3.养成良好的编码风格

4.添加必要的注释

5.避免编码的陷阱

 6.2示例:

模拟实现strcpy

 将*strSource中的数据放到*strDestination,strcpy在拷贝字符串的时候,会把源字符串中的\0也拷贝过去

 第一次改进

但是此时还是有缺陷,这里传参的时候,可能会将空指针传过来,所以我们需要断言一下

 第二次改进

但是这里还是有缺陷有的人可能不小心将dest的内容传到src中

 第三次改进,在char*src前面用const修饰,src的内容就不能被更改

注意:在库函数中,strcpy返回的是char*,所以还要再修改一下

 第四次修改

为什么返回char*类型?

是为了实现链式访问

strcpy函数返回的是目标空间的起始地址

注意:

1.分析参数设计(命名,类型)。返回类型的设计

2.这里讲解野指针,空指针的危害

3.assert的使用,这里介绍assert的作用

4.参数部分从上图的使用,这里讲解const修饰指针的作用

5.注释的添加

6.3const的作用

 num前被const修饰num的值就不能被更改

但是此时采用指针的方式可以将num的值更改,但是我们不想要num的值被更改,我们应该怎么办呢? 

 此时在*p前加const,*p的值就不能被更改了

const修饰指针变量

  • const放在*的左边

const int*p=&num;

int const *p=&num;

上面这两种的写法是等价的 ,此时*p的值是不允许更改

意思是:p指向的对象不能通过p来更改了,但是p变量本身的值是可以改变的

const int num=10;

const int*p=&num;

int n=100;

p=&n;//此时可以更改p的值

printf("%d\n",num);

  • const放在*的右边 

意思是:p指向的对象是可以通过p来改变的,但是不能修改p变量本身的值 

#include<stdio.h>
int main()
{
    const int num=10;
    int* const p=&num;
    *p=0;//ok
    int n=100;
    p=&n;//err
}

7.编程常见错误

7.1编译型错误

直接看错误提示信息,解决问题,或者凭借经验就可以搞定,相对来说简单

语法错误是再编译期间发现的问题,也是编译错误

7.2链接型错误

看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标示符名不存在或者拼写错误

比如:LNK201 无法解析的外部符号

一般是看报错给的名字,可能是没引调用函数的头文件,也可能引用函数的头文件了,但是名字拼写错误(注意:并且大小写要一致)

声明:

extern 函数的类型名 函数名 ((函数参数的类型)函数参数);//引用另一个文件时用extern

7.3运行时错误

借助调试,桌布定位问题。运行错误比较难搞。

通常时借助于调试解决的

tip:

release版本和debug版本优化也有所差异

debug版本会陷入死循环

 而release版本会做相应的优化

 这个程序和环境有很大的关系

release版会做相应的优化

release版本将内存开辟顺序发生了改变

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值