十.实用调试技巧(1)

C语言至此算是一个小结,相信大家对C语言已经有了一个初步的理解,所以C语言的初阶到这便结束了。学完C语言的初阶,大家应该能独自写出一段代码了。但是能写代码当然也就会存在bug(可不敢说我的代码就是标准实例,不可能有错误,大家还是要谦虚一点嗷,hahaha),有错误、有bug我们就要去把它找出来,这就需要用到本章的知识——代码调试技巧了。话不多说,正文开始!


  • 什么是bug
  • 调试是什么
  • debug和release的介绍
  • Windows环境的介绍
  • 一些调试的实例
  • 如何写出易于调试的代码
  • 编程常见的错误

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

1.什么是bug

       程序错误,即英文的Bug,也称为缺陷、臭虫,是指在软件运行中因为程序本身有错误而造成的功能不正常、死机、数据丢失、非正常中断等现象。 早期的计算机由于体积非常庞大,有些小虫子可能会钻入机器内部,造成计算机工作失灵。史上的第一只 "Bug" ,真的是因为一只飞蛾意外走入一电脑而引致故障,因此Bug从原意为臭虫引申为程序错误

 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

2. 调试是什么

引入

        所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象。迹象越多就越容易顺藤而上,这就是推理的途径。顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。一名优秀的程序员是一名出色的侦探,每一次调试都是尝试破案的

-- -- -- -- -- -- -- -- -- -- -- -- -- -- --

我们平时是怎么写代码的呢

是这样的吗

-- -- -- -- -- -- -- -- -- --

又是如何排查出现的问题的呢

还是这样去调试呢

 你们是这样的吗~~(反正本长老有时候差不多,嘿嘿嘿)

但很显然,这并不是好的写代码习惯和调试的好习惯,我们应当拒绝迷信式调试!!!!

-- -- -- -- -- -- -- -- -- -- -- -- -- -- --

调试是什么

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

       程序调试是将编制的程序投入实际运行前,用手工或编译程序等方法进行测试,修正语法错误和逻辑错误的过程。这是保证计算机信息系统正确性的必不可少的步骤。编完计算机程序,必须送入计算机中测试。根据测试时所发现的错误,进一步诊断,找出原因和具体的位置进行修正

-- -- -- -- -- -- -- -- -- -- -- -- -- -- --

调试的基本步骤

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

 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

3.DebugRelease的介绍

调试版本

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

 

 在调试版本下看一看可执行程序的大小

-- -- -- -- -- -- -- -- -- -- -- -- -- -- --

发布版本

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

 想要看到发布版本,需要先转换成Release版本,再把你写得代码编译一下,这样才会在你的路径中生成一个Release版本的文件夹,将其打开可以看见:

 可以发现,再Release版本中,可执行程序的(.exe/.e)文件的大小变小了。这是因为Release版本下,代码会被做一系列的优化,大小当然也会变小。而且Release版本中并不带有调试信息,即你不可以在这个版本进行调试(不信你可以按Fn+F10试试)

-- -- -- -- -- -- -- -- -- -- -- -- -- -- --

DebugRelease反汇编展示对比

想要看汇编代码需要先Fn+F10开始调试,再右击鼠标点击”转到反汇编“ 

Debug环境下

 Release环境下

 对比可发现,发布版本下的汇编代码量明显少于调试版本的

-- -- -- -- -- -- -- -- -- -- -- -- -- -- --

那编译器进行了哪些优化呢

前面我们了解到,Release会在大小上进行优化,但其实Release还会在代码的功能上进行优化

先看一段代码,来猜一下结果

#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++)
   {
        arr[i] = 0;//改变数组值
        printf("shizhanglao\n");
   }
    return 0;
}

经过前面的学习,我们能够很容易的发现,在经过多次循环后(i>9之后),就会对数组进行越界访问,那么编译器是会报错的(比如本长老使用的编译器——vs2022)。但从逻辑上来说,数组越界应该是错误访问,为什么会一直循环下去呢,这与代码运行时的内存分配有关

在以前的章节多次提到,计算机内存中有栈区、堆区和静态区,而局部变量、函数形参等都是在栈区中开辟储存空间的

不同的内存区域有不同的使用习惯

  • 内存开辟在栈区的使用习惯是:先用高地址处的空间,再用低地址处的空间
  • 数组的空间开辟使用习惯是:先用低地址,再用高地址

由于变量i先创建,所以在数组的上面,那么它们在内存中的分布就是这样的。因此,在数组越绝访问之后,是有可能会访问到i并把i的值改为0的(因为不确定越界访问两个元素够不够访问到i,可能i后面空了更多的字节才去创建数组arr)那么i又被改为0的话,循环条件将一直判断为真,不会再停下来,从而出现死循环(当然编译器很可能会察觉到这一点,并阻止你的越界访问)

 那我们来看看这段有问题的代码再Release环境下的表现

 

 代码竟然编译成功了,虽然在第九行仍然报了一个警告,但却没有再弹出报告错误的弹窗

此时我们再来看看两个变量的地址发生了什么变化,由于在Release环境下,代码不能编译,自然也不能使用监视和看内存,所以可以直接把地址打印出来

 运行后可以看到,在Release环境下,编译器居然把i和arr的地址给换了,把变量i创建的位置放在了数组arr的后面(因为i的地址比arr的地址小了,i在低地址处了)

即变量在内存中开辟的顺序发生了变化,影响到了程序执行的结果
由此可见,Release环境下编译器还会再对代码的功能进行优化

 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

①想要进一步了解Bug的概念,可以看看Bug的百度百科链接

②想要进一步了解调试的概念,可以看看程序调试的百度百科链接

③因为编译器会报错,当然就无法演示死循环的具体表现了

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世长老

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值