Visual Studio的实用调试技巧总结

news/2024/10/15 12:29:47/

        对于很多学习编程的老铁们来说,是不是也像下面这张图一样写代码呢?

        那当我们这样编写代码的时候遇到了问题?大家又是怎么排查问题的呢?是不是也像下面这张图一样,毫无目的的一遍遍尝试呢?

        这篇文章我就以 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环境 中的结果展示:

#include<stdio.h>int 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版本会对代码进行各种优化,因此这种版本也并不适合我们进行调试。

        那编译器进行了哪些优化呢?再来看看下面这段代码在两种环境下的结果展示:

#include<stdio.h>int 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 没用,就试试 Fn+F5,其他快捷键也是一样的。如果忘记这些快捷键了,Visual Studio上也有提示的。

        当进行调试后,就能看到以下窗口,记住一定要调试启动后才能看到

3. 如何写出好(易于调试)的代码

        对于一份优秀的代码,通常会有以下几个特性:

                1. 代码运行正常。
                2. bug很少。
                3. 效率高。
                4. 可读性高。
                5. 可维护性高。
                6. 注释清晰。
                7. 文档齐全。

4. 常见的coding技巧

        1. 使用assert 。
        2. 尽量使用const。
        3. 养成良好的编码风格。
        4. 添加必要的注释。
        5. 避免编码的陷阱。

这里给大家讲解一下第一点assert。

        assert是一个库函数(调用是需要包含头文件:#include<assert.h>),又为 断言 —— 只要不符合assert内的判断则会报错,反之则代码正常运行。

        举例如下:

        当我们用 assert 来判断所传的地址是否为空地址时,如果不为空,则代码正常运行,反之则报错(Assertion failed: p != NULL),这样通过assert函数就能很好的指出代码的问题。

5. 常见的编译错误

        1. 编译型错误:直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。(一般找到的都是语法问题)
        2. 链接型错误:看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不存在或者拼写错误。
        3. 运行时错误:借助调试,逐步定位问题。最难搞。

 

        最后就是如果我们想要在将来写出一份优秀的代码,一定要熟练掌握调试技巧,并且多使用快捷键,提升效率。只有多动手,尝试调试,我们才能有进步!!


http://www.ppmy.cn/news/1539435.html

相关文章

从0到1封装一个image/pdf预览组件

目录结构 content.vue <template><div class"no-content-block"><i class"iconfont icondocument large-file" /><div class"text-wrapper">{{ t(__ui__.siPreview.previewSupported) }}</div><div class&quo…

基于ffmpeg实现多路rtsp拉流解码为yuv420p

一&#xff1a;前言 FFmpeg 是一个非常强大的多媒体框架&#xff0c;它可以用来处理视频和音频数据。它包括了命令行工具 ffmpeg、ffplay、ffprobe 等&#xff0c;以及一套可以用来开发多媒体应用的库&#xff08;libavcodec、libavformat、libavutil、libswscale 等&#xff0…

LangChain使用Prompt02

1.设置提示 from langchain.prompts import ChatPromptTemplate prompt_template ChatPromptTemplate.from_messages([("system", "你是一位专业的翻译&#xff0c;能够将{input_language}翻译成{output_language}&#xff0c;并且输出文本会根据用户要求的任…

云原生周刊:优化 Uber 的持续部署丨2024.10.14

开源项目推荐 Cog Cog 是将机器学习模型打包到容器的工具。可通过配置将机器学习模型所需的环境和依赖&#xff0c;自动打包到容器里方便部署&#xff0c;让你不再为编写 Docker 文件和 CUDA 而痛苦&#xff0c;还能自动启动 HTTP 接口服务方便调用。 KnowStreaming KnowSt…

基于FreeRTOS的LWIP移植

目录 前言一、移植准备工作二、以太网固件库与驱动2.1 固件库文件添加2.2 库文件修改2.3 添加网卡驱动 三、LWIP 数据包和网络接口管理3.1 添加LWIP源文件3.2 Lwip文件修改3.2.1 修改cc.h3.2.2 修改lwipopts.h3.2.3 修改icmp.c3.2.4 修改sys_arch.h和sys_arch.c3.2.5 修改ether…

架构设计笔记-18-安全架构设计理论与实践

知识要点 常见的安全威胁&#xff1a; 信息泄露&#xff1a;信息被泄露或透露给某个非授权的实体。破坏信息的完整性&#xff1a;数据被非授权地进行增删、修改或破坏而受到损失。拒绝服务&#xff1a;对信息或其他资源的合法访问被无条件地阻止。攻击者向服务器发送大量垃圾…

【浏览器】如何正确使用Microsoft Edge

1、清理主页广告 如今的Microsoft Edge 浏览器 主页太乱了&#xff0c;各种广告推送&#xff0c;点右上角⚙️设置&#xff0c;把快速链接、网站导航、信息提要、背景等全部关闭。这样你就能得到一个超级清爽的主页。 网站导航       关闭 …

mysql--数据表的操作

说明&#xff1a;filed为列名 关于数据表的操作 目录 1、创建表 2、查看表结构 &#xff08;1&#xff09;显示表结构 &#xff08;2&#xff09;显示具体表信息 3、修改表结构 &#xff08;1&#xff09;删除表 &#xff08;2&#xff09;修改表名 &#xff08;3&am…