vs调试技巧(非常重要)

目录

第一个bug

调试是什么,有多重要?

熟悉一些快捷键 

调试功能栏

如何写出好的(易于维护)的代码


推荐书籍:《C陷阱与缺陷》

第一个bug

第一个计算机bug的发现可以追溯到1947年9月9日,由美国海军编程员、编译器的发明者格蕾斯·哈珀(Grace Hopper)发现。当时,哈珀中尉正领着她的小组构造一个称为“马克二型”的计算机,这是一个使用大量继电器的电子机械装置。在一次运行中,马克二型突然死机,技术人员经过排查,发现第70号继电器出错,而在这个出错的继电器中,哈珀发现了一只飞蛾。她小心地用镊子将飞蛾夹出,用透明胶布帖到“事件记录本”中,并注明“第一个发现虫子的实例”。从此以后,人们将计算机错误戏称为Bug,与之相对应,人们将发现Bug并加以纠正的过程叫做“Debug”,意即“捉虫子”或“杀虫子”。格蕾丝·哈珀后来成为了美国海军的一位将军,还领导了著名计算机语言Cobol的开发。

 调试是什么,有多重要?

所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。
顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。

一名优秀的程序员是一名出色的侦探。
每一次调试都是尝试破案的过程。

 

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


调试的基本步骤
● 发现程序错误的存在

● 以隔离、消除等方式对错误进行定位

● 确定错误产生的原因

● 提出纠正错误的解决办法

● 对程序错误予以改正,重新测试
 

Debug和Release

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。

每一次运行程序时,如果是调试版本或发布版本都会在一个文件夹产生一个Debug文件或Release文件,里面包含了一个可执行文件。

熟悉一些快捷键 

F9在某一行设置断点(如下图的红点),程序一直执行到这一行就会停下来(如果断点之前的代码没有bug、死循环、scanf等),再按一下F9取消断点。

鼠标右击这个断点,可以对这个断点进行设置:

 再点击“条件”:

可以设置在程序执行到断点时达到什么样的条件才停下来,这个功能可以用在循环(不用一直按F10)。 

F5 :启动调试,经常用来跳到下一个断点。如果成功跳到下一个断点,断点会变成这样:

 我们可以根据断点是否会变成这样来判断这个断点与上一个断点之间的代码有没有bug。

F10:逐语句执行代码,会跳过函数调用的过程。

F11:也是逐语句执行代码,但不会跳过函数调用的过程。

更多快捷键

调试功能栏

按下 F10 开始调试: (蓝色框为下文要介绍的功能)

查看断点

在调试功能栏点击断点,可以查看当前存在的所有断点

可以在这个窗口取消这个断点:

自动窗口和局部变量窗口

这两个功能可以自动监视程序中出现的局部变量,而不用手动输入要监视的变量

但是不能手动输入要监视的变量,也不能删除正在监视的变量,而且进入其他函数又只能监视本函数的局部变量,所以这种监视不灵活。

 监视

就是以上窗口的“升级”,它在调试过程中可以任意添加或删除要监视的变量。它还所以做一些运算,如 a + 1,甚至求一个表达式的布尔值。

观察指向数组的指针指向的数组的元素的值时,要在输入指针名后加逗号和数组元素个数。

比如:

数组名作为参数传到其他函数时,往往监视不了该数组:

解决方法(如下图):在监视窗口的数组名后面加上一个逗号和你要监视的数组元素的个数,如果在逗号后面输入大于数组元素的数,也就是超出数组的范围, 会观察到内存中的随机值。

查看内存 

内存窗口可以观察到全局变量、局部变量、数组元素的值,里面的值以十六进制显示(倒着显示),实际上内存中还是以二进制补码存储一个数

先设置每行显示 4 :(每行显示 8 个十六进制数字,每行就是 4 个字节,观察起来方便)

再输入你想观察的变量、数组的地址: 

输入 &a 观察局部变量 a 的值

 输入 &b 观察全局变量 b 的值

 

输入 arr 观察数组元素的值

反汇编

在调试时,可以右击鼠标转到反汇编,查看当前代码的汇编代码

查看寄存器 

在调试功能栏中有寄存器,点击后可以查看寄存器:

如果知道寄存器的名字,也可以在监视窗口输入寄存器的名字

查看调用堆栈

当代码工程量很大时,函数的调用逻辑可以用调用堆栈窗口来很好观察

 经典调试案例:

#include <stdio.h>
int main() 
{
    int i = 0;
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    for (i = 0; i <= 12; i++)
    {
        printf("hehe\n");
        arr[i] = 0;
    }
    return 0;
}

上面的代码陷入了死循环,为什么?经过调试发现 arr[12] 的地址与 i 的地址相同。

如何写出好的(易于维护)的代码

 优秀的代码:

1.代码运行正常                             4. 可读性高

2. bug很少                                   5. 可维护性高 

3. 效率高                                       6. 注释清晰

7. 文档齐全

常见的coding技巧:
 

1. 使用assert (断言)

基本形式:

  assert(表达式);

作用:当表达式为假,程序运行时报错 ,如果为真,就啥事都不发生

需要包含头文件 include <assert.h>

2. 尽量使用const   

被 const 修饰的变量仍然可以被指向它的变量修改,如:

const int a = 10;

int* p = &a;

*p = 20 // a 的值被改为20。

我们想的是 a 变量的值是不能被修改的,但指针变量却可以修改它。

解决方法是定义指针时也加上 const ,如:

(1)const 在 * 的左边

const int*p = &a;

也可以写成:

int const *p = &a;

两种写法 const 都是修饰 *p 的,表示 p 所指向的内容不能被修改,但 p 的指向可以被修改。

*p = 20;// error

p = &n;//ok

(2)const 在 * 的右边

如果写成 int * const p = &a; 则 p 的指向不能修改,但 p 所指向的变量的值可以修改。

p = &a;//error

*p = 20;//ok

strcpy函数:

 使用 Everything 找库函数源码:

strlen 的源码:

  

3. 养成良好的编码风格

4. 添加必要的注释 

5. 避免编码的陷阱。

编程常见的错误

编译型错误
直接看错误提示信息(双击错误提示信息,会有箭头指向有错误的那一行) , 解决问题。或者凭借经验就可以搞定。相对来说简单。

链接型错误
看错误提示信息 , 主要在代码中找到错误信息中的标识符 , 然后定位问题所在。一般是没有包含头文件、标识符名不存在或者拼写错误(大小写)

 使用搜索检查:


使用 ctrl + F 搜索:

 

运行时错误
借助调试,逐步定位问题。最难搞。
 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值