资讯详情

【C语言】调试技巧

大家好,我是泽(~o ̄) . 我相信你在编写C程序时会遇到很多代码Bug.因此,本博客将带您如何调试C技能,这样在遇到错误代码时,也不必惊慌,只需调试,Bug再也不存在了,哈哈哈哈~隔。

??什么是bug?

??臭虫:

?什么是调试?

??调试的基本步骤

??Debug和Release

??Debug:

??Release:

??本质区别:

??Debug 版本:

??Release 版本:

?Release版本优化:

??运行和调试常用的快捷键

??查看程序的信息

??如何写好代码?

??优秀的代码

??常见的coding技巧

??assert代码使用:

什么是bug?

bug:Bug原意:可称为臭虫",现在指的是漏洞,它出现在安全系统上缺陷,攻击者可以攻击未经授权的情况,Bug(计算机漏洞) 可以描述各个领域的漏洞。

臭虫:

  • 中文常称BUG为了缺陷。此外,缺陷一词可以更好地反映事物的本质。因为臭虫从外面飞进来,而不是程序本身。程序本身的问题是程序已经存在的。因此,它将在这里BUG更适合翻译成系统漏洞。

第一代计算机由许多巨大而昂贵的真空管组成,并利用大量的电力使真空管发光。也许是计算机运行产生的光和热引起了一只小虫子(Bug)钻进真空管,使整个计算机无法正常工作。研究人员花了半天时间终于发现了原因。从真空管中取出虫子后,计算机恢复正常。后来,Bug用这个词来表示计算机系统或程序中隐藏的错误、缺陷和漏洞。

1945年,计算机仍由机械继电器和真空管驱动,机器像房间一样大。反映了当时的技术水平MarkⅡ,是哈佛大学制造的庞然大物。当技术人员不整机运行时,它突然停止工作。他们爬上去寻找原因,发现这台巨大的计算机内部一组继电器的接触点之间有一只飞蛾,这显然是由于光和热的吸引,飞到接触点,然后被高压杀死。与Bug相应地,人们会发现Bug纠正的过程称为Debug(中文称为调试),意思是抓虫或杀虫。


什么是调试?

调试其实就是找出bug,计算机有bug一定是你的程序问题。所有程序问题都有痕迹可循,我们只需要最后一步一步地解决。

调试:英文DeBug,又称除错,是在计算机程序设备中发现和减少电子仪器错误的过程。

调试的基本步骤

  • 发现程序的错误:
  1. 程序员(写程序)
  2. 软件测试人员(测试程序的重要性)

程序员成本最低,用户成本最高。


Debug和Release

Debug:

通常为调试版本,它包含调试信息,不会优化,方便程序员调试信息。

概念:

1937年,美国青年霍华德·艾肯找到IBM该公司投资200万美元开发计算机,第一款成品艾肯将其命名为:马克1号(mark1),又称自动序列受控计算机IBM公司由生产制表机,肉铺磅秤,咖啡研磨机等待乱七八糟的行业,正式进入计算机领地。为马克1号编程的是哈佛女数学家格蕾丝·霍珀,有一天,她在那里调试程序故障发生时,打开继电器后,发现一只飞蛾被夹在触点中间,从而卡住了机器的运行。因此,霍珀幽默地称程序故障为臭虫...(BUG)DEBUG,这个奇怪的名字后来成为计算机领域的专业行话。debug意思是排除程序故障。

称之为发布版本,它往往是根据各种进行了优化,使得程序的代码都是最佳优的,以便让用户更好的去使用。

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。

Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。还有大小的区别,因为Debug的版本是可以进行调试的(包含了相应的调试信息),而Release版本是不能进行调试的。

Debug 和 Release 的真正秘密,在于一组编译选项。

下面列出了分别针对二者的选项

(当然除此之外还有其他一些,如/Fd /Fo,但区别并不重要,通常他们也不会引起 Release 版错误,在此不讨论)

Debug 版本:

/MDd /MLd 或 /MTd 使用 Debug runtime library(调试版本的运行时刻函数库)

/Od 关闭优化开关

/D "_DEBUG " 相当于 #define _DEBUG,打开编译调试代码开关(主要针对 assert函数)

/ZI 创建 Edit and continue(编辑继续)数据库,这样在调试过 程中如果修改了源代码不需重新编译 /GZ 可以帮助捕获内存错误

/Gm 打开最小化重链接开关,减少链接时间

Release 版本:

/MD /ML 或 /MT 使用发布版本的运行时刻函数库

/O1 或 /O2 优化开关,使程序最小或最快

/D "NDEBUG " 关闭条件编译调试代码开关(即不编译assert函数)

/GF 合并重复的字符串,并将字符串常量放到只读内存,防止 被修改

实际上,Debug 和 Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。

  • 采用Debug的话,如果用Debug代码来编译可执行程序的话,我们也会产生一个Debug的版本的一个可执行程序
  • 采用Release的话,就是发布版本,可执行的程序。——(简化)

Release版本优化:

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    int i = 0;
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    for(i=0;i<=12;i++)
    {
        printf("hello C\n");
        arr[i] = 0;
    }
    system("pause");
}

大家可以分别试一下就会发现不同之处了,分别用Debug和Release运行以下程序。这里是当你for循环的结果为假的时候,它的i又会重置为0,然后一直这个样子重复循环打印for语句的循环内容。因为arr这里跟i它们两个人是同一块空间,那么当你改变arr[i]的时候int i也会改变。因为它们的地址是一样的,所以才会改变。

由于这个程序涉及范围到栈区一些相关的知识点的内容,在这里我跟大家简单的说下。

栈区:栈区的默认使用是先使用高地址处的空间,然后在使用低地址处的空间。数组的下标随着增长,地址是由低到高变化的。当然如果你在不同的编译器上运行它的死循环的位置可能不同。你们也可以在不同的编译器上运行一下对比一下


运行与调试常用的快捷键 

调试:F11:是逐步 它是会进入函数的 把程序细化到步

shift + F11,跳出函数

F10 是逐行 在某条语句调用一个函数的时候 它不会进入(除非那里设有断点)

F9:切换断点

使用快捷键F11可以快速调试当前选中的资源文件。

断点调试操作:F5、F6、F7、F8

F5和F9的快捷键可以进行配合使用。


查看程序的信息

ctrl + F5:开始执行不调试,如果你想让程序而不调试就可以进行使用。

自动窗口:当我们程序在执行中的时候,打开自动窗口,自动的把某些程序的上下文变量自动给你观察,这就是自动窗口的功能。

局部变量:和自动窗口差不多其实,但是它有一个缺点是它不能想监视谁就监视谁。

监视:监视这个作用就比较好了,当你想监视的话就输入那个变量的值,它就会呈现在你的监视当中,这样你就可以随时随地的去进行观察那个变量了。(监视窗口可以说是博主用的最多的了)

内存:如果我们想进行观察当前程序执行的内存的话,这个时候就是你输入观察的内存信息了。

(内存窗口也是用的可以说是非常多的了)

调用堆栈:在这里简单的和各位小伙伴们说下,像栈一样的逻辑给大家给展示出来它的一个逻辑,顶上往前放数据再往顶上出数据,可以很好反馈程序当中的代码的调栈的调用逻辑。


如何写出好的代码?

优秀的代码

  • 代码整洁且规范
  • 注释清晰,且通俗易懂(代指写代码的人)
  • 可读性,有效性,可维护性
  • bug尽量能够达到自己能够预期的范围之内,就是bug少,或者几乎没有bug
  • 文档齐全,不乱去堆放 

常见的coding技巧 

  • 尽量使用const
  • 使用assert,头文件#include<assert.h>,在assert();里面的表达式如果为真的话,assert表达式为真就什么都不会发生,如果assert的表达式为假,那么就会报错。

在这里简单的跟大家介绍一下const的关键字:const修饰的数据是常类型,常类型的变量或者对象的值是不可以被该变的,也就是被它修饰过的是常量,相比之下const常量和#define是有点类似的,但是在我们用数组的时候还是要区分一下,因为数组里面 [常量表达式],此时我如果 const int n = 10 假设赋值给arr数组,int arr[n] = {0};结果是不行的,虽然加了const关键字,但实际上也只是变量只不过是不能被修改的变量。那么如果我们这里用的是#define—定义符号常量就可以了。  

assert代码使用:

#include<stdio.h>
#include<assert.h>
int My_strlen(const char* pb)
{
	int Count = 0;//计数
	assert(*pb != NULL);//保证指针的有效性 NULL —— 空指针
	while (*pb != '\0')
	{
		Count++;
		*pb++;
	}
	return Count;
}
int main(void)
{
	char arr[20] = "nihao C";
	int ret = My_strlen(arr);
	printf("arr(strlen) = %d\n", ret);
	return 0;
}

标签: mt03i热继电器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台