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

C/C++程序的断点调试 - Visual Studio Code

本文以Visual Studio Code为例,简述C/C++程序断点调试的基本方法和过程。其它的IDE环境,大同小异。

本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

1. 简介

在程序有BUG/缺陷,需要修复时,断点调试是发现缺陷的重要方法。对于初学者而言,断点调试还有另外一个用途:帮助理解程序背后的逻辑。

本文以Visual Studio Code为例,简述C/C++程序断点调试的基本方法和过程。其它的IDE环境,大同小异。

在进行后续调试试验前,需要先对Visual Studio Code的C/C++编译开发环境进行配置。详细过程请参见下述链接:http://codelearn.club/2022/09/vsccpp/

2. 程序代码

在Visual Studio Code中创建一个纯C语言的代码文件DebugExample.c,然后录入如下代码:

//Project - DebugExample
#include <stdio.h>
#include <stdbool.h>

bool isPrime(int n) {     //函数的定义
    if (n<=1)
        return false;
    for (int i=2;i<n;i++)
        if (n % i == 0)
            return false;

    return true;
}

int main(){
    printf("Try to find all prime number(<=10):\n");

    int iFound = 0;       //发现的质数个数
    for (int i=2;
         i<=10;
         i++)
    {
        if (!isPrime(i))
            continue;
        iFound++;
        printf("%d, ",i);
    }

    printf("\n%d prime numbers been found.",iFound);
    return 0;
}

在作者的机器上,该文件被存放在D:\TEMP目录下。

上述程序的用途在于找出2 ~ 10之间的全部质数并打印出来。请读者注意第19 ~ 21行,for循环的初始化语句,测试表达式,更新表达式故意分作了三行,以便于观察。

3. 断点

在这里插入图片描述

在第18行代码的行号左边单击鼠标,便会出现如图所示的断点(break point),在相同位置再次单击,断点便会消失。可以给同一段程序添加多个断点。

4.调试

在这里插入图片描述
在打好断点后,选择菜单Run-Start Debugging(F5)开始调试。在这里插入图片描述
此处依提示选择了C++(GDB/LLDB)。
在这里插入图片描述
此处选择了第一项:C/C++: gcc.exe生成和调试活动文件。
在这里插入图片描述
与正常的程序运行不动,程序并没有“一口气”从头执行到尾,而是暂停在了第18行的断点处。图中的黄色箭头表明程序的当前执行点,准确地说,箭头所指的行是接下来准备执行的代码行。

在窗口的左上角,VARIABLES(变量)项上列出了程序当前执行阶段的局部变量的名称及当前值。可以看到,此时有iFound变量存在,其值为0。

注意:此时iFound的0值是不确定的,事实上,0到iFound的赋值尚未执行。
在这里插入图片描述
此外,主界面上还会出现一个工具条,其名称依次是Continue, Step Over, Step Into, Step Out, Restart 以及Stop。这些按钮均有快捷键与之对应,详情请查看Run菜单。
在这里插入图片描述
点击Step Into(单步进入),可以看到第18行被执行,黄色箭头指向第19行。此时,for循环内的局部变量i出现在左侧列表中。请读者注意此时i的当前值为0,而不是2,因为for循环的初始化语句尚未执行。

注意:在变量没有被初始化前,其值是不确定的,所以读者真实调试时,得到的值很可能不是0。
在这里插入图片描述
再次点击Step Into,第19行被执行,可见左侧列表中的i值变成了2。黄色箭头来到了第20行,这是for循环的条件判断表达式。
在这里插入图片描述
继续按下Step Into,for循环在进行了条件判断后,准备执行循环体,黄色箭头来到第23行。

第23行涉及一次函数调用,如果操作者希望观察isPrime( )函数内部的执行过程,应按Step Into。如果操作者不关心isPrime( )内部的执行过程,只关心23行的总体执行结果,则按Step Over。本次,我们按Step Into。
在这里插入图片描述
按下Step Into后,我们进入到了isPrime( )函数内部,黄色箭头指向第6行。对于isPrime( )函数而言,当前其局部变量仅有1个,即函数的形式参数n。该参数的值应由调用者传递进来。在右方的列表中,我们看到该值为2。
在这里插入图片描述
一直按Step Into,直到isPrime( )函数返回,由于2是质数,所以第23行的不是质数的条件不成立,第24行不会被执行,黄色箭头略过了第24行,指向了第25行。
在这里插入图片描述
再次按Step Into后,第25行被执行,iFound由0变1,黄色箭头指向第26行。
在这里插入图片描述
一直按Step Over进行循环,直到i = 4且黄色箭头指向第23行。
在这里插入图片描述
本次我们选择不进入isPrime()函数,再次按下Step Over。由于i=4不是质数,因此第23行的条件成立,黄色箭头跳转到第24行的continue语句。

根据continue的语义,其将略过本轮循环的剩余语句(第25 ~ 26行),直接尝试下一轮循环。
在这里插入图片描述
按下Step Into,可以看到,continue直接略过了第25 ~ 26行的剩余循环代码,直接跳到了for循环的更新表达式,如图中红色箭头所示。
在这里插入图片描述
按下Step Into, 可以看到更新表达式被执行,i值由4变成了5,黄色箭头指向了第20行,该行将进行循环测试(i <= 10),如果测试通过,则将执行循环体,否则循环结束。

5.观察输出

在这里插入图片描述
在程序调试过程中,随时可在下面工具栏中切换至TERMINAL(终端)页,该页面中展示了程序当前执行阶段的全部输出。如果程序在执行过程中需要读取输入,也应在该页录入。

可以看到,2,3两个质数已被找出,4是合数被略过,正准备考察整数5。

6. 去除断点

如果调试的目的已达成,准备放弃调试,可以再次单击红色断点将其取消,如下图:
在这里插入图片描述
在这里插入图片描述
此时,可以选择Continue (继续执行,F5),在没有断点的情况下将程序执行完;也可以选Stop Debugging,强行中止程序的执行。

7. 继续执行

取消断点后,我们选择了继续执行。程序执行完成后,IDE中与调试相关的箭头,局部变量列表等均消失不见,恢复至常规编辑界面。
在这里插入图片描述
在Terminal页,我们看到程序的全部执行结果。

为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

简洁的C及C++
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造
Python编程基础及应用
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造

如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

Python编程基础及应用

Python编程基础及应用实验教程
在这里插入图片描述

相关文章:

  • 墨家在中国为什么消失得这么彻底?
  • 面试必备:分库分表经典15连问
  • 微信支付-全面详解(学习总结---从入门到深化)
  • 【MySQL】数据库基础知识汇总和增删改查操作
  • 【云计算与大数据技术】文件存储格式行式、列式、GFS、HDFS的讲解(图文解释 超详细)
  • 股票l2接口的委托数据有什么作用?
  • 人工智能:智能语音技术应用场景介绍
  • JSP ssh流量充值系统myeclipse开发oracle数据库MVC模式java编程计算机网页设计
  • [附源码]Python计算机毕业设计非处方药的查询与推荐系统Django(程序+LW)
  • 简洁而优美的结构 - 并查集 | 一文吃透 “带权并查集” 不同应用场景 | “手撕” 蓝桥杯A组J题 - 推导部分和
  • 12月13日(第11天)
  • 【华为机试真题详解】优选核酸检测点【2022 Q4 | 100分】
  • 浅谈责任链设计模式在框架源码中的运用
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116
  • 力扣(LeetCode)1832. 判断句子是否为全字母句(C++)
  • [译] React v16.8: 含有Hooks的版本
  • 《剑指offer》分解让复杂问题更简单
  • CentOS从零开始部署Nodejs项目
  • go语言学习初探(一)
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • Web设计流程优化:网页效果图设计新思路
  • 欢迎参加第二届中国游戏开发者大会
  • 排序算法学习笔记
  • 时间复杂度与空间复杂度分析
  • 想写好前端,先练好内功
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • scrapy中间件源码分析及常用中间件大全
  • 容器镜像
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • #预处理和函数的对比以及条件编译
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET 药厂业务系统 CPU爆高分析
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项
  • .NET处理HTTP请求
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • ;号自动换行
  • @kafkalistener消费不到消息_消息队列对战之RabbitMq 大战 kafka
  • @NoArgsConstructor和@AllArgsConstructor,@Builder
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [AI]ChatGPT4 与 ChatGPT3.5 区别有多大
  • [AIGC] Nacos:一个简单 yet powerful 的配置中心和服务注册中心
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [ASP.NET 控件实作 Day7] 设定工具箱的控件图标
  • [autojs]autojs开关按钮的简单使用
  • [Avalon] Avalon中的Conditional Formatting.
  • [BJDCTF2020]The mystery of ip