当前位置: 首页 > news >正文

Visual Studio的实用调试技巧总结

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

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

        这篇文章我就以 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. 运行时错误:借助调试,逐步定位问题。最难搞。

 

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

相关文章:

Visual Studio的实用调试技巧总结

对于很多学习编程的老铁们来说&#xff0c;是不是也像下面这张图一样写代码呢&#xff1f; 那当我们这样编写代码的时候遇到了问题&#xff1f;大家又是怎么排查问题的呢&#xff1f;是不是也像下面这张图一样&#xff0c;毫无目的的一遍遍尝试呢&#xff1f; 这篇文章我就以 V…...

graphrag学习总结

学习视频&#xff1a;b站链接 项目链接 GraphRAG 的基本概念 Document&#xff08;文档&#xff09;&#xff1a;系统中的输入文档。这些文档要么代表CSV中的单独行&#xff0c;要么代表单独的txt文件。 TextUnit&#xff08;文本块&#xff09;&#xff1a;要分析的文本块。…...

专题:贪心算法(已完结)

1.分发饼干 方法一&#xff1a;用最大的胃口 找到最大的饼干&#xff08;先遍历胃口&#xff09; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {// 主要思路 用最大的饼干找最大的胃口sort(g.begin(),g.end());so…...

Hadoop的三种运行模式:单机模式、伪分布式模式和完全分布式模式

单机模式 单机模式是Hadoop最简单的运行模式。在单机模式下&#xff0c;所有Hadoop组件都运行在单个机器上&#xff0c;包括HDFS、MapReduce等。由于只有一个节点参与计算&#xff0c;单机模式适用于开发和测试阶段&#xff0c;不适合用于处理大规模数据。在单机模式下&#xf…...

JavaScript将array数据下载到Excel中

具体代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widt…...

【前端】Bootstrap:快速开始

Bootstrap 是一个功能强大且易于使用的前端框架&#xff0c;专门用于创建响应式和移动优先的网页。学习Bootstrap不仅可以帮助你快速构建现代网页&#xff0c;还可以提升你对前端开发流程的理解。本教程将从基础概念开始&#xff0c;逐步引导你掌握Bootstrap&#xff0c;并通过…...

文献阅读(222) VVQ协议死锁

题目&#xff1a;VVQ: Virtualizing Virtual Channel for Cost-Efficient Protocol Deadlock Avoidance时间&#xff1a;2023会议&#xff1a;HPCA研究机构&#xff1a;KAIST request-reply协议死锁如下图所示&#xff0c;每个node收到request之后发送reply&#xff0c;但是想…...

Node.js管理工具NVM

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理多个 Node.js 版本的工具。以下是 nvm 的使用方法和一些常见命令&#xff1a; 一、安装 nvm 下载 nvm&#xff1a; 地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases访问 nvm 的 GitHub 仓…...

云原生后端

云原生后端&#xff08;Cloud-Native Backend&#xff09;是指在云计算环境中&#xff0c;利用云原生技术&#xff08;如容器、微服务、服务网格等&#xff09;构建和部署后端应用程序的一种方法。以下是对云原生后端的详细讲解&#xff1a; 1. 定义 云原生是一种设计和构建应…...

充电宝哪个品牌值得买?2024年五款靠谱充电宝推荐

哪个品牌充电宝值得买&#xff1f;用过这么多款充电宝&#xff0c;个人还是觉得充电快、小巧便携的充电宝使用会更加的方便&#xff01;在当今快节奏的生活中&#xff0c;手机已成为我们不可或缺的伙伴。然而&#xff0c;随着智能手机功能的日益强大&#xff0c;电池续航问题也…...

YOLOv11对比YOLOV8网络结构变化分析,帮助你真正的理解和学习yolo框架

本文在大佬的文章YOLOv11 | 一文带你深入理解ultralytics最新作品yolov11的创新 | 训练、推理、验证、导出 &#xff08;附网络结构图&#xff09;基础上做了一些补充。 一、YOLOv11和YOLOv8对比 二、YOLOv11的网络结构图 下面的图片为YOLOv11的网络结构图。 三、YOLOv11…...

弃用RestTemplate,RestClient真香!

在Spring框架的发展历程中&#xff0c;RestTemplate作为发起HTTP请求的同步API&#xff0c;曾经扮演着举足轻重的角色。然而&#xff0c;随着技术的不断进步和微服务架构的普及&#xff0c;RestTemplate的局限性逐渐显现&#xff0c;尤其是在处理高并发和异步请求时。因此&…...

electron-vite_10electron-updater软件更新

网很多electron-updater更新文章&#xff0c;这里只简单写一下演示代码&#xff1b; 为什么选择 electron-updater插件可以自动更新应用程序,同时支持多个平台;比官方要强; 官方的autoUpdater仅支持macOS 和 Windows 自动更新; 注意是自动&#xff0c;直接更新那种; 脚手架中是…...

React native之全局变量存储AsyncStorage

AsyncStorage是React native中对变量&#xff0c;对象进行全局存储&#xff0c;读取的异步使用对象。以key值进行存储。但是只能存储字符串数据&#xff0c;想存储对象&#xff0c;可把对象JSON进行序列化存储&#xff0c;读取的时候再转成JSON对象。 AsyncStorage.getItem()-…...

获取vue实例

需要注意的是&#xff0c;无论通过哪种方式获取元素&#xff0c;如果元素为 vue 组件&#xff0c;则需要在子组件中使用 defineExpose 进行暴露。 在父组件中&#xff0c;我们静态绑定 childRef&#xff1a; 在子组件中&#xff0c;我们需要通过defineExpose函数&#xff0c;手…...

基于Python实现电影推荐系统

电影推荐系统 标签&#xff1a;Tensorflow、矩阵分解、Surprise、PySpark 1、用Tensorflow实现矩阵分解 1.1、定义one_batch模块 import numpy as np import pandas as pddef read_and_process(filename, sep ::):col_names [user, item, rate, timestamp]df pd.read_cs…...

【linux】进程理解

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;linux笔记仓 目录 01.进程的基本概念进程的组成部分进程的特性进程的状态 02.PCBPCB的组成部分task_structtask_struct 的主要组成部分 03.进程属性查看进程 04.通过系统调用创建进程-fork初识工作…...

文件IO练习1

题目一&#xff1a; 1、使用fread和fwrite完成两个文件的拷贝&#xff0c;要求源文件和目标文件由外界输入 实现代码&#xff1a; #define LEN_BUF 256int main(int argc, const char *argv[]) {if(argc ! 3){fprintf(stderr,"程序入参输入有误\n");return -1;}FILE…...

c++ std::future 和 std::promise 的实现工作原理简介

为了便于理解 std::future 和 std::promise 的实现工作原理&#xff0c;我们可以创建一个简化的版本。这包括共享状态、Promise 设置值、Future 获取值的核心机制。我们的示例代码将实现 SimplePromise 和 SimpleFuture 两个类&#xff0c;二者通过一个共享状态实现线程间的通信…...

MATLAB(Octave)混电动力能耗评估

&#x1f3af;要点 处理电动和混动汽车能耗的后向和前向算法模型(simulink)&#xff0c;以及图形函数、后处理函数等实现。构建储能元数据信息&#xff1a;电池标称特性、电池标识符等以及静止、恒定电流和恒定电压等特征阶段。使用电流脉冲或要识别的等效电路模型类型配置阻抗…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...