网站被入侵,庆阳网站制作,wordpress关闭GZIP,全国各城市感染高峰进度查询对于很多学习编程的老铁们来说#xff0c;是不是也像下面这张图一样写代码呢#xff1f; 那当我们这样编写代码的时候遇到了问题#xff1f;大家又是怎么排查问题的呢#xff1f;是不是也像下面这张图一样#xff0c;毫无目的的一遍遍尝试呢#xff1f; 这篇文章我就以 V… 对于很多学习编程的老铁们来说是不是也像下面这张图一样写代码呢 那当我们这样编写代码的时候遇到了问题大家又是怎么排查问题的呢是不是也像下面这张图一样毫无目的的一遍遍尝试呢 这篇文章我就以 Visual Studio 2022编译器为例带大家了解在Visual Studio2022编译器上是 如何进行调试C语言代码的。
1. 调试是什么有多重要
1.1 调试的概念 调试是什么调试英文Debugging / Debug又称除错是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
1.2 调试的基本步骤 1.发现程序错误的存在。 2.以隔离、消除等方式对错误进行定位。 3.确定错误产生的原因。 4.提出纠正错误的解决办法。 5.对程序错误予以改正重新测试。
1.3 Debug和Release的介绍 Debug: 通常称为调试版本它包含调试信息并且不作任何优化便于程序员调试程序。 Release: 称为发布版本它往往是进行了各种优化使得程序在代码大小和运行速度上都是最优的以便用户很好地使用。(该版本不方便程序员调试)。
1.4 Debug和Release版本的对比 因此我们平常在编译器中写代码时都是用的Debug版本。并且我们说调试就是在Debug版本的环境中找代码中潜伏的问题的一个过程。 对于如下同一份代码我们来看看在 Debug环境 和 Release环境 中的结果展示
#includestdio.hint main()
{int arr[] { 1,2,3,4,5,6 };int* p arr;printf(%d\n, *(p 2));return 0;
} Debug环境中 Release环境中 由结果中可以看出Release环境下的执行文件(即 .exe文件)会比 Debug环境下的执行文件小好几倍这是因为Release版本会对代码进行各种优化因此这种版本也并不适合我们进行调试。 那编译器进行了哪些优化呢再来看看下面这段代码在两种环境下的结果展示
#includestdio.hint main()
{int i 0;int arr[10] { 0 };for (i 0; i 12; i){arr[i] 0;printf(hahaha\n);}return 0;
} 同样的代码在Debug环境中死循环在Release环境下却能正常运行。这时我们通过调试看看这段代码在两种环境下的反汇编展示对比 观察两种环境下的汇编指令可以看出Release版本会删除一些不必要的指令从而使得编译器在运行代码时速度上是最优的。 这时候也许有老铁会疑惑为什么这段代码在Debug环境下死循环报错(依赖于编译器的环境在x86环境下会死循环x64环境下会报错)呢下面我就给大家仔细讲讲。 首先要知道的是局部变量在内存中的栈区上开辟空间的而栈区内存空间的使用习惯先使用高地址处的空间再使用低地址的空间 (在不同的编译器上有所区别)如下图所示 而数组随着下标的增长地址是由低到高变化的且数组内存是连续存储的。因此上述代码中通过for循环对数组进行越界访问并对数组元素重新赋值为0这样就可能会导致arr[10] —— arr[12]中所开辟的内存空间 与 局部变量i 所开辟的内存空间重叠从而导致 变量i 的值被修改为0进而陷入死循环。 这也提醒我们在对数组进行访问时千万不能越界访问呀
2. Windows环境调试介绍 在对代码进行调试前一定要将编译器的环境设置为 Debug版本这样才能正常调试 2.1 Visual Studio中常用的一些快捷键 F5 —— 启动调试经常用来直接跳到下一个断点处(切换断点)。 F9 —— 创建断点和取消断点。断点的重要作用可以在程序的任意位置设置断点。这样就可以使得程序在想要的位置随意停止执行继而一步步执行下去。 F10 —— 逐过程通常用来处理一个过程一个过程可以是一次函数调用或者是一条语句。(逐过程简单的说就是当遇到函数调用时直接就执行完成了而不会进入到函数内部。) F11 —— 逐语句就是每次都执行一条语句但是这个快捷键可以使我们的执行逻辑进入函数内部这是最常用的。(逐语句简单点说就是当遇到调用函数时会进入函数内部逐一执行每条语句。) CTRL F5 —— 开始执行不调试如果你想让程序直接运行起来而不调试就可以直接使用。
如果直接按 F5 没用就试试 FnF5其他快捷键也是一样的。如果忘记这些快捷键了Visual Studio上也有提示的。 当进行调试后就能看到以下窗口记住一定要调试启动后才能看到 3. 如何写出好易于调试的代码 对于一份优秀的代码通常会有以下几个特性 1. 代码运行正常。 2. bug很少。 3. 效率高。 4. 可读性高。 5. 可维护性高。 6. 注释清晰。 7. 文档齐全。
4. 常见的coding技巧 1. 使用assert 。 2. 尽量使用const。 3. 养成良好的编码风格。 4. 添加必要的注释。 5. 避免编码的陷阱。
这里给大家讲解一下第一点assert。 assert是一个库函数(调用是需要包含头文件#includeassert.h)又为 断言 —— 只要不符合assert内的判断则会报错反之则代码正常运行。 举例如下 当我们用 assert 来判断所传的地址是否为空地址时如果不为空则代码正常运行反之则报错(Assertion failed: p ! NULL)这样通过assert函数就能很好的指出代码的问题。 5. 常见的编译错误 1. 编译型错误直接看错误提示信息双击解决问题。或者凭借经验就可以搞定。相对来说简单。(一般找到的都是语法问题) 2. 链接型错误看错误提示信息主要在代码中找到错误信息中的标识符然后定位问题所在。一般是标识符名不存在或者拼写错误。 3. 运行时错误借助调试逐步定位问题。最难搞。 最后就是如果我们想要在将来写出一份优秀的代码一定要熟练掌握调试技巧并且多使用快捷键提升效率。只有多动手尝试调试我们才能有进步