新手一定要掌握的实用调试技巧(vs2019)

news2024/11/25 20:50:59

目录 

1、什么是bug?

2、调试是什么?

        2.1、调试是什么

        2.2、调试的基本步骤

        2.3、Debug和Release的介绍

3、Windows环境调试介绍

        3.1、调试环境的准备

        3.2、学会快捷键

        3.3、调试的时候查看程序当前信息

                3.3.1、查看临时变量的值

                3.3.2、查看内存信息

                3.3.3、查用调用堆栈

                3.3.4、查看汇编信息

                3.3.5、查看寄存器信息

4、调试的实例 

6、如何写出好(易于调试)的代码

        6.1、优秀的代码

        6.2、示范

        6.3、const的作用

如何使用const和理解const int* 和int *const 的区别

7、编程常见的错误

        7.1、编译型错误

        7.2、链接型错误 

 7.3、运行时错误


1、什么是bug?

BUG的英文释义是“虫子”,现在人们将再电脑系统或程序中,隐藏着的一些未被发现的缺陷或问题统称为bug(漏洞),人类历史上第一个程序BUG就是与虫子有关。

1937年,一个年轻的美国小伙找到IBM公司要了200万叨做计算机,第一台成品取名为“马克1号”,写代码的是一个小妮·雷斯·霍波。有一天,他在调试程序时出现故障,经过一阵子周折,发现有只飞蛾被烤糊在两个继电器触电的中间导致短路。于是把程序故障统称为“臭虫BUG”。从此这只虫子名垂千古,永远的保存在了华盛顿的美国国家历史博物馆中

2、调试是什么?

        2.1、调试是什么

一般指的你写的代码,在Debug模式下编译以后,编译器在你的代码里插入了调试信息,你可以一步一步运行程序,查看中间结果,适用于你程序运行不对,需要检查中间过程确定问题源头的时候。

        2.2、调试的基本步骤

  • 发现程序错误的存在
  • 以隔离、消除等方式对错误进行定位
  • 确定错误产生的原因
  • 提出纠正错误的解决办法
  • 对程序错误予以改正,重新测试

        2.3、Debug和Release的介绍

  • Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序
  • Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用
  • 可在编译器此处选择配置

3、Windows环境调试介绍

        3.1、调试环境的准备

在环境中选择 debug 选项,才能使代码正常调试

        3.2、学会快捷键

下面是调试常用的快捷键:

F5: 启动调试,经常用来直接跳到下一个断点处(若没有断点将运行整个程序)
F9:创建断点和取消断点。断点的重要作用,可以在程序的任意位置设置断点。这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去
F10:逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句
F11:逐语句,就是每次都执行一条语句,但是这个快捷键可以使执行逻辑进入函数内部,这是最常用的
Ctrl+ F5:开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用

        3.3、调试的时候查看程序当前信息

注意:以下所有内容都是在调试开始后才可操作的

                3.3.1、查看临时变量的值

四个监视窗口都可以用,只需要在监视名称是输入合法的监视内容即可

                3.3.2、查看内存信息

与监视窗口同理,四个口都可以用

在地址处输入你要查询的地址,在列处可以自己进行选择

选定后回车即可查看 

                3.3.3、查用调用堆栈

                3.3.4、查看汇编信息

                3.3.5、查看寄存器信息

4、调试的实例 

#include <stdio.h>
int main()
{
	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	for (i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
	}
	return 0;
}

调试如下

6、如何写出好(易于调试)的代码

        6.1、优秀的代码

优秀的代码应具有:1.代码运行正常

                                 2.bug很少

                                 3.效率高

                                 4.可读性高

                                 5.可维护性高

                                 6.注释清晰

                                 7.文档齐全

我们常见的coding技巧有:1.使用assert

                                           2.尽量使用const

                                           3.养成良好的编码风格

                                           4.添加必要的注释

                                           5.避免编码陷阱

        6.2、示范

对于上述我们所说coding技巧我们将在下面这个例子进行实现

这里呢我们模拟实现库函数:strcpy

首先呢,我们先看一下这个函数的参数和返回值类型

 返回值类型为char*,参数都为char*,const后续会讲到,接下来我们进行实现,先写出主函数如下:

//int main()
//{
//	char arr1[] = "hello bit";
//	char arr2[20] = "xxxxxxxxxxxxx";
//	printf("%s\n", my_strcpy(arr2, arr1));
//	return 0;
//}

当我们不知道使用const时我们的写法是这样的

//char* my_strcpy(char* dest, char * src)
//{
//	char* ret = dest;//由于后面++操做会使dest所指向的地址发生变化,所以这儿提前将首地址存入ret
//	while (*dest = *src) 
//	{
//      dest++;
//      src++;
//  }
//	return ret;//返回ret,也就是最初的dest,方便后续printf打印
//}

而这个代码其实我们还可以进行优化,优化如下

//char* my_strcpy(char* dest, const char * src)
//{
//	char* ret = dest
//	while (*dest++ = *src++) //进行了优化
//		;//空语句
//	return ret;
//}

 但是呢使用者不知道我们应该怎么给参数,如果使用者一不小心给了一个空指针呢比如下面

 我们发现代码并没有报错,还是走了下去,但这是不是我们需要的呢?显然不是,这时候我们就需要使用前面所讲的assert(断言),搭配头文件#include <assert.h>使用

断言(assertion)是一种在程序中的一阶逻辑(如:一个结果为真或假的逻辑判断式),目的为了表示与验证软件开发者预期的结果——当程序执行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止执行,并给出错误信息。

使用如下

​
char* my_strcpy(char* dest, const char * src)
{
	//	//断言
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	while (*dest++ = *src++) //进行了优化
		;//空语句
	return ret;
}

​

我们测试一下看一下使用效果

我们发现它不在不作为,而是给你报出你的代码在什么路径下哪里出现错误,我们这里显示第8行出现错误,而我们地8行接受到了空指针, 所以程序会中止执行,并给出错误信息。

 

当我们搞定这些之后我们又出现了问题, 有个粗心的小伙伴在实现时,把*dest++ = *src++写反了,写成了 *src++=*dest++ ,此时我们发现程序正常运行,但给出的结果时错误的,者我们该怎么解决呢?这时候就需要用到我们接下来所要讲到的const了

        6.3、const的作用

const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一定帮助。

const修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的。

主要作用
1、可以定义const常量,具有不可变性
2、便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { …} 编译器就会知道i是一个常量,不允许修改;
3、可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。
4、节省时间和提高效率,编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高

我们先简单看一下吧

我们发现在对n进行修改时,编译器进行报错了,因为n不能被更新

如何使用const和理解const int* 和int *const 的区别

以一个简单的代码例子来解释

#include <stdio.h>

void test1()
{
	int n = 10;
	int m = 20;
	int *p = &n;
	*p = 20;
	p = &m; 
}
void test2()
{
	int n = 10;
	int m = 20;
	const int* p = &n;
	*p = 20;
	p = &m; 
}
void test3()
{
	int n = 10;
	int m = 20;
	int *const p = &n;
	*p = 20; 
	p = &m; 
}

int main()
{
	//测试无cosnt的
	test1();
	//测试const放在*的左边
	test2();
	//测试const放在*的右边
	test3();
	return 0;
}

  

我们测试后发现 

test1()函数可以正常运行,而test2 ( )和test3()不可以。
test2()中的const int* p = &n;的const的作用是使指针不能改变指向当前地址的值,也就是说,此时n等于10,不能通过指针p来改变n的值。*p=20;此时这句话会报错。
test3()中的int *const p = &n;的const的作用是使指针不能改变当前所指向的地址。也就是说,此时p指向的是n的地址,而不能再改变去指向m的地址。p = &m; 这句话会报错

总结如下

/const 修饰指针的时候
129当const 放在*的左边的时候,限制的是指针指向的内容,不能通过指针变量改变指针指向的内容,但是指针变量的本身是可以改变的
130当const 放在*的右边的时候,限制的是指针变量本身,指针变量的本身是不能改变的,但是指针指向的内容是可以通过指针来改变的

则my_strcpy()函数完整实现如下

//char* my_strcpy(char* dest, const char * src)
//{
//	char* ret = dest;
//	//断言
//	assert(dest != NULL);
//	assert(src != NULL);
//
//	while (*dest++ = *src++) 
//		;//空语句
//
//	return ret;
//}

7、编程常见的错误

        7.1、编译型错误

直接看到错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单

双击错误就可以跳到问题行 

        7.2、链接型错误 

看错误提示信息,主演是在代码中找到错误信息中的标识符,然后定位问题所在。一般标识符不存在或者拼写错误

如上述拼写错误,我们进行编译后发现

 7.3、运行时错误

借助调试,逐步定位问题,最难搞。需要慢慢积累经验。

 

制作不易,一键三连!!一起加油!!!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/574314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【PWN · IntegerOverflow ret2text】[BJDCTF 2020]babystack2.0

第一次遇见整数溢出的题目&#xff0c;值得记录一下&#xff08;虽然这里的整数溢出很简单 目录 前言 一、整数溢出 二、解题思路 1.ELF/checksec查看保护 2.IDA反汇编 3.整数溢出 4.exp编写 总结 前言 整数溢出漏洞——对于有/无符号数&#xff0c;长/短位宽转换时机…

什么是 Spring Boot Actuator?如何在 Spring Boot 中使用 Actuator?

当我们在开发和部署应用程序时&#xff0c;监控应用程序的健康状况和性能是非常重要的。Spring Boot Actuator 为我们提供了一组现成的端点&#xff08;endpoints&#xff09;&#xff0c;可以让我们方便地监控和管理应用程序。在本文中&#xff0c;我们将了解 Spring Boot Act…

Spark+Kafka构建实时分析Dashboard

SparkKafka构建实时分析Dashboard 说明一、案例介绍二、实验环境准备1、实验系统和软件要求2、系统和软件的安装&#xff08;1&#xff09;安装Spark&#xff08;2&#xff09;安装Kafka&#xff08;3&#xff09;安装Python&#xff08;4&#xff09;安装Python依赖库&#xf…

数据仓库hive本地/远程模式安装

文章目录 1.简述2.本地模式2.1安装包准备2.2解压安装mysql2.2.1 解压mysql安装包2.2.2 安装mysql相关组件2.2.3 修改my.cnf配置文件2.2.4 更改所属组2.2.5 启动mysql服务 2.3 hive解压安装及配置2.3.1 解压2.3.2 改名2.3.3 配置环境变量2.3.4 添加hive-site.xml配置文件2.3.5 放…

《Spring Guides系列学习》guide6 - guide10

要想全面快速学习Spring的内容&#xff0c;最好的方法肯定是先去Spring官网去查阅文档&#xff0c;在Spring官网中找到了适合新手了解的官网Guides&#xff0c;一共68篇&#xff0c;打算全部过一遍&#xff0c;能尽量全面的了解Spring框架的每个特性和功能。 接着上篇看过的gu…

VIBRO METER 带缓冲输出的机械监控系统接口套件

高质量、高可靠性的接口套件&#xff0c;用于现有机械监控系统的缓冲“原始”传感器输出信号。该接口套件支持多达25个通道&#xff0c;可以是动态或转速计(速度)信号。接口套件采用DIN导轨安装&#xff0c;通常安装在装有VM600或VibroSmart机械监控系统的外壳中。 特征 支持…

为 Kotlin 的函数添加作用域限制(以 Compose 为例)

前言 不知道各位是否已经开始了解 Jetpack Compose&#xff1f; 如果已经开始了解并且上手写过。那么&#xff0c;不知道你们有没有发现&#xff0c;在 Compose 中对于作用域&#xff08;Scopes&#xff09;的应用特别多。比如&#xff0c; weight 修饰符只能用在 RowScope 或…

docker快速部署hue+hue集成hive

首先需要安装hive&#xff0c;hive的安装在HIVE的安装与配置_EEEurekaaa&#xff01;的博客-CSDN博客 安装完成之后&#xff0c;使用脚本命令启动hdfs和hive的相关服务。 一、安装docker # 安装yum-config-manager配置工具 $ yum -y install yum-utils # 设置yum源 $ yum-co…

《俞军产品方法论》- 站在更高的角度来拓展产品经理的内涵和边界

关于作者 俞军&#xff0c;互联网产品大神级人物。他是早年百度唯一的产品经理&#xff0c;主持了百度搜索这款产品的无数次进化&#xff0c;并主持设计了百度贴吧、百度 知道等世界级创新产品&#xff0c;后来又成为滴滴出行的产品负责人。他的 “ 俞军产品经理十二条 ” &a…

TexSAW|2023|Cryptography&Misc|WP

Cryptography&#xff5c;Crack the crime 用 nc 连上后&#xff0c;直接得到第一题 是一个简单的base64加密&#xff0c;解密如下&#xff1a; Meet in dubai on Tuesday 填入之后可获得第二题 猜测是古典加密&#xff0c;随后经过N次尝试后发现是rot13加密&#xff0c;解密…

蓝牙耳机怎么选?蓝牙耳机哪些性价比高?2023年蓝牙耳机推荐,蓝牙耳机品牌排行榜,蓝牙耳机最全选购指南

蓝牙耳机怎么选&#xff1f;蓝牙耳机哪些性价比高&#xff1f;2023年蓝牙耳机推荐&#xff0c;蓝牙耳机品牌排行榜&#xff0c;蓝牙耳机最全选购指南 观前提醒&#xff0c;本文中你将会了解到&#xff1a; &#xff5c;蓝牙耳机抄作业环节 &#xff5c;蓝牙耳机基础知识 &a…

快速上手kettle

一、前言 最近由于工作需要&#xff0c;需要用到kettle工具进行数据迁移转换。特意找资料学习了一下&#xff0c;kettle基本操作算是学会了。 所学的也结合实际工作进行了验证。为了防止以后用到忘记了&#xff0c;便写了几篇文章记录一下。 二 、ETL简介 ETL ( Extract-Tran…

synchronized 关键字和 volatile 关键字有什么区别?

synchronized 关键字和 volatile 关键字有什么区别&#xff1f; 在 Java 中&#xff0c;synchronized 关键字和 volatile 关键字都可以用来实现线程安全&#xff0c;但是它们有不同的用途和实现方式。本文将介绍 synchronized 关键字和 volatile 关键字的区别&#xff0c;包括…

二肽二氨基丁酰苄基酰胺二乙酸盐/Dipeptide Diaminobutyroyl Benzylamide Diacetate/SYN-AKE

作用机理----二肽二氨基丁酰苄基酰胺二乙酸盐 类蛇毒三肽通过松弛面部肌肉而作为有效的平滑和祛皱活性产品, 该活性三肽作用方式与 Temple Viper 毒蛇毒液的神经肌肉阻断化合物Waglerin 1 一致。类蛇毒三肽作用于突触后膜, 是肌肉烟碱乙酰胆碱受体(nmAChR)可逆转的拮抗剂。类蛇…

docker安装单机nacos、rocketmq、reids、xxl-job、minio、elasticsearch、kibana

启动容器报错 直接删除那个name后边的就可以 安装nacos 首先需要拉取对应的镜像文件&#xff1a;docker pull nacos/nacos-server 挂载目录&#xff1a; mkdir -p /mydata/nacos/logs/ #新建logs目录mkdir -p /mydata/nacos/init.d/ vim /myda…

使用 Kotlin 的 Opt-in (选择加入)功能注解API提示当前非稳定API

前言 之前在给公司项目封装库的时候&#xff0c;领导告诉我封装的漂亮一点&#xff0c;等以后公司发展起来了可能需要把这个库提供给第三方接入使用。 此时&#xff0c;就有这么一个问题&#xff1a;某些功能函数使用条件比较苛刻&#xff0c;直接使用可能会出现意想不到的后…

Mock.js 的语法规范学习

Mock.js 有一套完整的语法规范,可以好好学学。 Mock.js 的语法规范包括两部分&#xff1a; 数据模板定义规范&#xff08;Data Template Definition&#xff0c;DTD&#xff09; 数据占位符定义规范&#xff08;Data Placeholder Definition&#xff0c;DPD&#xff09; 数…

【mediasoup】12: ChannelRequest控制指令

rust 是把worker 当做lib 调用的。node是当做一个进程每一个ChannelRequest 就是一个外部发给worker的控制指令worker要负责处理。控制指令的处理实际是worker做的,worker可能立即执行,可能交给对应的handler去处理 worker根据指令id 来处理 处理完毕后才发消息ack 给控制侧 …

# Spring Boot 中如何使用 Spring Cloud Sleuth 来实现分布式跟踪?

Spring Boot 中如何使用 Spring Cloud Sleuth 来实现分布式跟踪&#xff1f; 在微服务架构中&#xff0c;通常会有多个服务相互协作&#xff0c;为了方便排查问题&#xff0c;我们需要对服务之间的调用进行跟踪。Spring Cloud Sleuth 是 Spring Cloud 生态中的分布式跟踪解决方…

charles使用

charles​ 一、概念​ charles是一款非常优秀的抓包工具&#xff0c;全平台支持&#xff0c;在mac&#xff0c;windows&#xff0c;linux上都可以使用&#xff0c;既可以抓 取web端的包&#xff0c;也可以抓app端的包。 ​ charles主要的功能包括如下几点&#xff1a; ​ 截取…