程序员养成金手指——调试造就优秀

简介: 正片开始👀Bug👏bug意为臭虫,计算机术语里就是幺蛾子,对,你的程序又出幺蛾子了。为什么要叫bug?关于这个还有段有趣的历史

正片开始👀

Bug👏

bug意为臭虫,计算机术语里就是幺蛾子,对,你的程序又出幺蛾子了。为什么要叫bug?关于这个还有段有趣的历史


有一天赫柏正愉快地敲着Mark Ⅱ的代码时,计算机突然就停止运作了,那时的计算机远不如现在小巧,赫柏他们只能一个个排查计算机庞大的处理器群,经过一段时间的排查后停机原因终于被找到了。原来是一只飞蛾被计算机的光和热吸引,触发了电脑的短路,当然这只可怜的飞蛾也一命呜呼了按理说一般人也就是把飞蛾拿走,然后重启下电脑也就完事了,但赫柏显然不是一般人她小心翼翼地把这只飞蛾拿了下来,然后把它工工整整地粘在了记事本上… …


这就是历史上第一个 bug 的诞生。


调试的重要性👏

我估计前期我们找 bug 都是用眼睛瞅,特别是我们这种大一的刚接触的,现在还好,到了以后需要写大工程的时候,眼瞅不头疼的才是大哥,对于一个成熟程序员20%时间写代码而80%时间在调试代码。

我们写代码就是一个推理的过程,整个流程的正确与错误都是有迹可循的,推理的途径就是这些迹象。

一名优秀的程序员就是一个优秀的侦探,找到迹象,顺流而下是错误,顺流而上是真相,调试就是我们破案的过程。

调试基本步骤👏

1.找错(进行隔离,消除来定位错误)

2.知道错因

3.寻找解决办法

4.纠正,重测


Debug与Release👏

Debug(Debugging),即排错,称为调试版本,不作任何优化,包含调试信息,便于我们调试程序。

Release ,即释放,成为测试版本,往往进行各种优化,让代码在大小和运行速度上都是最优的,面向用户,可以很好的使用。但是!注意Release版本是没法进行调试的,这种观点仅限于我当前知识面的限制,实际上Release也是可以的,下面是大佬对我的指正意见:

image.png

快捷键👏

在调试过程中,掌握一些快捷键会大大增加我们的效率。以vs2019为例,我们先会设置断点如图(行标左侧设置)

image.png

断点设置在需检查代码的任意位置,运行到这一步就会停下给我们报告。断点完F5调试,执行窗口弹出后就会发现调试就会出现更多内容,我框出来的在之前记录C语言学习时都有用到。

image.png

注意F5是调试,Ctrl+F5是运行,通常会使用会F5跳到想要的断点处,有些电脑上比较装怪,快捷键没反应的,建议多按一个Fn键试试,Fn是功能辅助键,相当于一个开关,本质上 F5+Fn = F5。需要强调的是逐语句和逐过程,如果你想看每个细节,不放过每一个角落就用逐语句,两者的力度是不一样的,逐过程会跳过代码里的函数部分。

vs玩家重点推荐 Ctrl+k+c,注释选中行;Ctrl+k+u,取消注释,熟练运用会很方便。

其余还有很多不赘述,下面准备了超全的实用快捷键用法:


想深入了解的铁子戳这里


除了用调试验证代码的正确性,还可以用于研究具体的问题,举个栗子:

这道题是Nice的面试真题

请说明下面代码是否能正常运?运行结果是什么?为什么会出现这个结果?
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf(“hehe\n”);
}
return 0;
}

这里当我们打开调试窗口直接开调:

image.png

OMG,是一样的。但我们这里的调试只能看到现象,他底层的原理我们要自己思考。

其死循环的逻辑大致是这样的,我们创建了一个变量i,arr,他们都是局部变量,而局部变量时放在栈上的,栈区上内存使用习惯是先使用高地址存储空间,再使用低地址。这里注意,我们开始给的十个大小的空间,i的变量是到12,这里明显是越界访问,但为什么没有报错停下来?结合我们刚刚监视的结果,我们再把格局打开:

数组随着下标的增长,地址是由低到高的变化,在我数组适当越界时,如果i和arr之间的空间适当的话,就有可能使arr向后越界时就访问到了i,造成了循环变量的i改变,最终会死循环。

image.png

这种错误其实存在偶然性,首先i和arr[12]相同,只是恰巧,但如果我把i换成11,结果就大相径庭了,我只形成了越界但没有改变循环变量i的值。其次,这个代码是严重依赖环境的,比如在VC 6.0里面i和arr就是连续的,gcc里面i和arr之间有一个空间。

打趣的是,我们在Release版本里面是不会报错并且会停下来,其实在刚刚的截图里面也是会报错的,但是!死循环停不下来,他根本没时间来报错。Rlease的优化并不是万能的,不要期待利用Release版本来掩盖代码的bug,最好的做法就是不要越界。


如何写出易于调试(优秀)的代码👏

1.硬性要求运行正常

2.bug少(估计没人敢保证零bug吧)

3.效率高

image.png

4.可读性高


5.可维护性(容易修改与二创)

6.注释(方便阅读)

7.文档齐全


常见的coding技巧👏

1.使用assert

意为断言,在代码执行前设的前哨,比如我们函数传参时,当我传的内容变成空指针,后面如果函数进行解引用操作,对于空指针解引用是会造成程序崩溃的,是很危险的,所以我们用assert当监护人能快一步该诉我们问题在这里;设置assert也是一个好习惯,面试官见了直呼老司机!

# include<assert.h>
void my_str(char* a, char* b)
{
  assert(a != NULL && b != NULL);//断言
  while (*b != '\0')
  {
    *a = *b;
    b++;
    a++;
  }
  *a = *b;
}
int main()
{
  char arr[10] = {0};
  char arr2[] = "bit";
  my_str(NULL, arr2); // 故意设成NULL程序会崩溃
  printf("%s\n", arr);
  return 0;
}

image.png

效果如上图就会显示断言失败。


2.尽量使用const

const我之前博客写过的常变量修饰符。

就上面模拟strcpy函数,如果有天有个内鬼改了你的代码,写成 *b = *a,就拷反了,编译器也会傻不拉叽的输出,尽管结果什么都没有。那怎么办呢?我在开头就定义好


char* my_str(const char *a,const char* b)

1

这样不管你咋改,我 *a,*b都是无法改变的。


注意const int *p=&a , const 在 * 左边时,修饰的是指针指向的内容,指针变量不影响 ;在 * 右边是,修饰指针本身,指针变量不能修改,其内容可以通过指针来改变。

3,形成良好的编码风格

4.注释!注释!注释!(好习惯讲三次)

5.避免编码陷阱


今天就到这里了,摸了家人们。


相关文章
|
Java 开发工具 Android开发
安卓应用成功运行实录
安卓应用成功运行实录
52 0
|
3月前
|
图形学 开发者 异构计算
《黑神话:悟空》中的性能优化与调试技术
【8月更文第26天】在游戏开发过程中,性能优化和调试是保证游戏流畅运行的关键环节。《黑神话:悟空》作为一款追求高质量画面和流畅体验的游戏,其背后的性能优化与调试技术尤为重要。本文将详细介绍游戏开发过程中所采用的各种性能优化技术和调试手段。
61 3
|
3月前
|
数据挖掘 数据库 数据安全/隐私保护
有这10个Python脚本加持,这才是网工的生产力!
有这10个Python脚本加持,这才是网工的生产力!
|
3月前
|
开发者 算法 虚拟化
惊爆!Uno Platform 调试与性能分析终极攻略,从工具运用到代码优化,带你攻克开发难题成就完美应用
【8月更文挑战第31天】在 Uno Platform 中,调试可通过 Visual Studio 设置断点和逐步执行代码实现,同时浏览器开发者工具有助于 Web 版本调试。性能分析则利用 Visual Studio 的性能分析器检查 CPU 和内存使用情况,还可通过记录时间戳进行简单分析。优化性能涉及代码逻辑优化、资源管理和用户界面简化,综合利用平台提供的工具和技术,确保应用高效稳定运行。
84 0
|
4月前
|
人工智能 IDE 前端开发
|
6月前
|
存储 程序员 编译器
VS实用调试技巧(检验程序的法宝)
VS实用调试技巧(检验程序的法宝)
32 0
|
6月前
|
程序员 Python
揭秘单步调试:掌握这一技能让你代码无懈可击
揭秘单步调试:掌握这一技能让你代码无懈可击
58 0
|
6月前
|
存储 机器人 程序员
Scratch3.0——助力新进程序员理解程序(六、监测)
Scratch3.0——助力新进程序员理解程序(六、监测)
81 0
|
存储 固态存储 Ubuntu
基于飞腾芯片的设计与调试入门指导
基于飞腾芯片的设计与调试入门指导
629 0
|
存储 程序员 编译器
【C/调试实用技巧】—作为程序员应如何面对并尝试解决Bug?
【C/调试实用技巧】—作为程序员应如何面对并尝试解决Bug?
148 0