bug 其实在一开始的英文中是小昆虫的意思
在1947年9月9日,葛丽丝·霍普(Grace Hopper)发现了第一个电脑上的bug。有一次Mark II突然宕机,整个团队都搞不清楚为什么电脑不能正常运作了。经过大家的深度挖掘,发现原来是一只飞蛾意外飞入了一台电脑内部而引起了故障(如图所示)。这个团队很快排除错误,并在日志本中记录下了这一事件。也因此,人们逐渐开始用“Bug”(原意为“虫子”)来称呼计算机中的隐错。现在在华盛顿的美国国家历史博物馆中还可以看到这个遗稿。
修补、改正软件程序错误的过程被称为调试。
发现程序错误的存在。
以隔离、消除的方式对错误进行定位。
确定错误产生的原因。
提出纠正错误的解决办法。
对程序错误予以改正或重构,重新测试。
比如说以下面这段代码为例
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
// 要求 求1!+2!+3!+...+n!
int i, j;
int sum = 0;
int ret = 1;
int n = 0;
scanf("%d", &n);
for ( i = 1; i <= n; i++)
{
for ( j = 0; j < i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
可是运行的结果却是下面这样子

明显与我们的预期不符啊
我们便开始调试程序
经过调试窗口我们发现
原来问题出现在这里

j一开始出现的数字是0
0乘上任何数都是0 最后的sum当然会是0啦
那我们将代码修改如下
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
// 要求 求1!+2!+3!+...+n!
int i, j;
int sum = 0;
int ret = 1;
int n = 0;
scanf("%d", &n);
for ( i = 1; i <= n; i++)
{
for ( j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
再运行试试

奇怪了 1!+2!+3!并不等于十五啊
这说明我们的程序又出现了问题
我们继续开始调试

那经过我们新一轮的debug 我们又发现了 原来啊ret的值再每次循环后没有重置 最终导致了这个错误
那么我们再每次进入循环后将ret的值重置为1
代码如下
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
// 要求 求1!+2!+3!+...+n!
int i, j;
int sum = 0;
int ret = 1;
int n = 0;
scanf("%d", &n);
for ( i = 1; i <= n; i++)
{
ret = 1;
for ( j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
运行结果如下

这个时候我们可以发现 代码就可以无bug完美运行啦
这就是一个完成的debug过程
Debug版本就是我们程序员使用的调式版本 它包含调试信息 且不做任何优化 便于程序员调试
Release版本就是一个发布版本 它会对程序做各种优化 使得程序在大小和运行速度上是最优的 以便于用户更好的使用
Release版本

Debug版本

我们可以很明显的发现两个程序的大小都不一样
我们再来看以下的代码
int main()
{
int i = 0;
int arr[10] = { 0 };
for ( i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
在release版本下

它没有报错 打印了13个 hehe
我们再回到debug版本下

我们惊奇的发现 它竟然进入了死循环
它们之间又什么区别呢?
这就是因为两个版本之间的优化不同所导致的
至于为什么会在debug x86环境下进入死循环
这里大家要首先知道两个知识点
数组随着下标的增长 地址由低到高不断变化
栈区中优先使用高地址进行压栈操作
下面我画图来为大家讲解一下

在数组越界访问到12的时候实际上修改了i的值 从而导致了死循环
这里提一嘴
vc6.0编译器上i和arr数组之间相隔的内存为1
vs中为2
gcc中为0

设置进入debug环境
F5 启动调试,经常用来直接跳到下一个断点处。
F9 创建断点和取消断点 断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。F10 逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。与F11的区别是它不进入函数内部
F11 逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)

我们可以使用shift + f9来查看变量的值

其他所有数据 包括内存 反汇编 寄存器这些 都可以通过调试 - - 窗口里面查看
以上就是本篇博客的全部内容啦 由于博主才疏学浅 所以难免会出现纰漏 希望大佬们看到错误之后能够
不吝赐教 在评论区或者私信指正 博主一定及时修正
那么大家下期再见咯