什么是bug
bug的本意是指昆虫、小虫、损坏、缺陷等意思,一般地,在程序设计中的术语,bug是在软件运行中因为程序代码本身有错误而造成的功能不正常、体验不佳、数据丢失、非正常中断、死机等现象。
调试是什么?有多重要?
调试是什么?
调试是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。在调试的过程中我们可以监控程序的每一个细节,包括变量、函数的调用过程、内存的变化等等。
调试的基本技巧
- 发现程序错误的存在;
- 以隔离、消除等方式对错误进行定位;
- 确定错误产生的原因;
- 提出纠正错误的解决办法;
- 对程序错误改正,重新测试。
Debug和Release的介绍
Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便于用户很好的使用。
代码:
#include<stdio.h> int main() { char* p = "hello"; printf("%s\n", p); return 0; }
以上代码在Debug环境的展示:
以上代码在Release环境下的展示:
反汇编对比:
所以我们说的调试就是在Debug版本的环境中,找到代码中的潜伏问题的过程。
编译器进行了那些优化呢?请看下面的代码:
#include<stdio.h> int main() { int i = 0; int arr[10] = { 0 }; for (i = 0; i <= 12; i++) { arr[i] = 0; printf("haha\n"); } return 0; }
如果是Debug模式去编译,程序的死循环。
但是如果是Release版本去编译的话,程序没有死循环。
Windows环境调试介绍
调试准备
在环境中选择debug选项,才能使代码正常调试。
学会快捷键
F5
启动调试
F9
创建断点和取消断点
F10
逐过程,一个过程可以是一次函数的调用,或者是一个语句。
F11
逐语句,就是每次执行一条语句,这个快捷键可以使我们进入函数的内部。
CTRL+F5
开始执行不调试。
调试的时候查看程序当前信息
查看临时变量的值
在调试开始之后,用于观察变量的值。
代码:
#include<stdio.h> int main() { int a = 0; a = 10; printf("%d", a); return 0; }
先按F10在菜单栏上面找到调试点击—>窗口—>点击监视
查看内存信息
也是相同的方法,点击窗口之后在点击内存。
查看调用堆栈
也是相同的方法,点击窗口之后再点击调用堆栈。
查看汇编信息
在调试开始之后,右键鼠标,选择反汇编
在调试开始之后,点击菜单栏上的调试,再点击窗口,就可以找到反汇编。
查看寄存器信息
在调试开始之后,选择菜单栏上的调试,再选择窗口,选择寄存器。
如何写出好(易于调试)的代码
优秀的代码
- 代码运行正常;
- bug很少;
- 效率很高;
- 可读性高;
- 可维护性高;
- 注释清晰;
- 文档齐全。
常见的技巧
- 使用assert
- 尽量使用const
- 养成良好的代码风格
- 添加必要的注释
- 避免代码的陷阱
案例:
模拟实现库函数strcpy()
代码如下:
#include<stdio.h> #include<assert.h> char* my_strcpy(char* arr2,const char* arr) { char* ret = arr2; //断言 assert(arr2 != NULL); assert(arr != NULL); while (*arr2++ = *arr++) ; return ret; } int main() { char arr[] = "abcd"; char arr2[20] = "XXXXXXXXXXX"; /*my_strcpy(arr2, arr); printf("%s", arr2);*/ printf("%s", my_strcpy(arr2, arr)); return 0; }
const的作用
修饰指针变量的时候:
- const如果再*号的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身是可以改变的。
- const如果再*号的右边,修饰的是指针变量本身,保证了指针变量的内容不能改变,但是可以通过改变指针变量的指向来改变内容。
编程常见的错误
编译类型错误
直接查看错误信息,解决问题。
链接型错误
一般是标识符名不存在或者拼写错误。
运行错误
借助调试,一步来排查。