本节以inchar.c为例,说明从设计到调试的全过程,以便学习。
13.6.1 一个简单的实例
【例13.11】要求将从键盘上输入的一个字符按下面格式输出,下面是一个运行示范。
Input:5Your input is:5
这是一个顺序执行过程,输入有提示信息,输出增加了说明。下面是含有错误的C语言程序,用来演示编译和排错的过程。
//inchar.cmain( ){ char ch; printf(/"input:/"); scanf(/"%d/", ch); printf(/"Your input is:%dn/", ch);}
13.6.2 编译程序
假设工程名为myc,源程序名为inchar.c。详细步骤不再赘述。
输入程序,检查输入无误之后,即可对程序进行编译。这里需要注意的一点是,初学者往往过分地依赖编译器,不重视编译运行之前的人工检查。有很多的小错误,如拼写错误等是完全可以自己检查出来的。应当逐步培养自己的查错能力。在编制大型软件时,这一点显得尤其重要。特别需要提醒的是,C语言的关键字在编辑窗里是以与文字不同的颜色显示的,如果它们也变成了相同颜色,说明这一行隐含了VC不能识别的符号。最常见的原因是混入中文不可见符号或者用中文符号代替英文符号,如中文逗号代替西文逗号。
对文件进行编译。如图13-1所示,操作命令已经加上所在文件的标识,所以其功能非常清楚。选择编译命令“Compile inchar.c”,编译结果出现3个警告信息,如图13-2所示。
图13-1 工程组成信息及Build菜单
目前需要掌握的最基本的3个命令介绍如下。
(1)“Compile inchar.c”命令用来编译文件inchar.c。如果不能通过,则不产生obj文件,并给出出错信息。如果通过,产生inchar.obj文件,也可能给出警告信息。如果有警告信息,则说明程序有不妥之处,应该排除,直到无警告信息。需要注意的是,有警告信息时,产生的obj文件可能会有错误,不能产生exe文件,或者运行结果不正确。第一次调试程序时,一般都要使用这一命令检查错误。编译系统会给出出错和警告的可能原因,这将有助于查错。
(2)“Build myc.exe”命令在编译文件inchar.c时,同时产生inchar.obj和myc.exe文件。如果程序有问题,又不影响产生obj文件的话,只显示警告信息的数目,不显示警告的内容,这是与“Compile inchar.c”命令的区别。另外,可执行文件不是以C的源程序文件名命名,而是以工程命名,所以产生的执行文件名是myc.exe,而不是inchar.exe。
(3)“Execute myc.exe”命令执行文件myc.exe。如果没有myc.exe,则自动执行编译程序产生myc.exe文件,然后执行myc.exe文件。
如果一开始就使用“Build myc.exe”命令,只给出有问题的信息,这时产生的执行文件可能得不到正确结果。一旦有了无错误信息的inchar.obj文件,就可以使用“Build myc.exe”命令产生myc.exe文件。
图13-2 编译信息
13.6.3 排错
由图13-2的警告信息可知,这个程序没有错误信息,具有继续产生执行文件的可能性。即使能产生执行文件,也能正常运行,但也应该养成排除所有警告信息的正确作风。由警告信息可以看出,程序没有包含定义printf和scanf函数的头文件,主函数的定义也不严格。假设将它改正为如下程序。
#include <stdio.h>int main( ){ char ch; printf(/"input:/"); scanf(/"%d/", &ch); printf(/"Your input is:%dn/", ch); return 0;}
编译正确,执行“Execute myc.exe”运行程序,如图13-3所示,Windows弹出一个DOS窗口来运行DOS程序,按屏幕上的提示,按任意键即可返回开发环境。
假设输入52,则输出52,但输入字符W时,程序输出-52,证明程序不正确。所以不要只取一种情况验证程序是否运行正确,应对各种可能的情况都进行验证。
图13-3 运行程序的DOS窗口及运行结果
可以启用Debug,观察表达式或变量的值,并设置断点或单步运行程序。这个示例程序比较简单,如图13-4所示,单步运行程序,即可直接看到变量的值。如果要在右边设置监视的变量,直接在Name栏下输入变量名即可。
图13-4 观察变量在程序运行期间的变化情况
由此可见,虽然输入字符w,但读给变量ch的不是字符值,而是数字。scanf和printf语句的格式不对,应该改为%c。因为输入数字,所以隐藏了这个错误。输入数字时正确,输入字符时错误。通过监视变量的变化情况,可以很容易地发现这是将格式符%c错写成格式符%d造成的。
修改后的正确程序如下:
#include <stdio.h>void main( ){ char ch; printf(/"input :/"); scanf(/"%c/", &ch); printf(/"Your input is:%cn/", ch);}
由于在程序设计中错误总是难免的,因此调试也是必不可少的,所以应该尽快熟悉调试环境,而熟悉的唯一途径就是多用。“实践出真知”说的也正是这个道理。
13.6.4 基本调试命令简介
1.设置和取消断点
设置和取消断点是通过选择右键菜单来实现的。断点是程序员在程序上做的标记,表示调试程序时,运行到该处应该暂停。如图13-5所示,在要设置断点处单击选择右键菜单命令“Insert/Remove Breakpoint”,在该行设置一个红色圆点表示断点。
图13-5 设置和取消断点示意图
如果要取消断点,在断点行再次使用右键,则出现“Remove Breakpoint”和“Disable Breakpoint”两个菜单命令。前一个表示将取消断点(红色圆点消失),后一个表示保留断点,但暂时不起作用(程序执行时忽略这个断点)。如果选择后一命令,则红色实心圆点的内部变成白色(图13-5中的红色圆圈),同时菜单命令变为“Enable Breakpoint”,以便将来选择该命令恢复断点。
可以在光标所在行直接使用F9功能键设置和取消断点,也可以用它激活保留断点,但设置保留断点必须使用右键菜单。
2.调试控制
若未设置断点,可按F10键(Step Over)进行调试,调试程序将停在main函数的开始处。一旦准备好程序,便可以开始调试,这时可使用其他所有功能。
可采用下述方法进行调试。
(1)一次执行一行,跳过一些函数,或单步调试所有函数。
(2)从当前位置执行到预先设立的断点。
(3)从当前位置执行到光标所在位置。
上述方法可以选择使用也可以混合使用。
如果对源程序作了修改,则应重新编译,然后再进行调试。事实上,修改源程序后再用Step Over或Trace Into命令企图再次调试时,VC将询问用户是否需要重新生成可执行文件。
3.调试命令和热键
表13-1列出了用于调试菜单的几个特别的调试命令和热键。
表13-1 常用调试命令
4.变量窗口
在如图13-4所示的程序窗口下面,左边的窗口称为变量窗口,用来显示各个变量及其取值。变量窗口有3个选项卡,分别是“Auto”,“Locals”和“this”。我们经常要查看前两个选项卡中的内容,这两个选项卡的作用如表13-2所示。随着程序的执行,如果选项卡中变量的值发生变化,则将它们用红色显示出来。
表13-2 变量窗口中的“Auto”与“Locals”选项卡
只要双击变量的值,就可以直接修改该变量的值。在调试时,可以很方便地改变变量的值,观察它们的行为。
5.观察窗口
在如图13-4所示的程序窗口下面,右边的窗口称为观察窗口。在变量窗口中,“Auto”和“Locals”选项卡中所显示的变量并不是当前函数中所有有意义的变量,而且在两个选项卡之间切换也不方便,所以常使用观察窗口来显示变量的值。
观察窗口共有4个选项卡,每一个选项卡中都可以任意输入变量。双击Name栏的空白处,即可输入任意变量,其值显示在Value栏中。双击变量的值,可以直接修改。
在观察窗口中,还可以输入一些简单的表达式,如“y+25”,Value栏中则显示这个表达式的值。
6.调试命令菜单
如图13-6所示,“Bulid”菜单含有可供调试程序的子菜单。使用这些调试命令可进入程序调试状态。
如图13-7所示,进入调试状态后,“Build”的位置被“Debug”菜单代替。图13-7还给出了执行断点行的示意图。
图13-6 Bulid菜单的调试命令
图13-7 Debug菜单及执行断点行的示意图
13.6.5 程序与汇编调试窗口
有时需要根据汇编窗口加以观察。下面的程序演示了内存数据的存放方式。
【例13.12】演示小端存储的程序。
#include <stdio.h>union s{ int n; char str[4];}uc;int main( ){ int i=0; uc.n=0x12345678; printf(/"0x%xn/",&uc); for(i=0;i<4;i++) printf(/"0x%x 0x%xn/",&uc.str[i],uc.str[i]); return 0; }
从图13-8的窗口可以看出,uc.str[0]存储的是0x78,对照7位ASCII编码表,0x78也是小写字母x的ASCII码。对比un.n=0x12345678,str[0]里存储的是0x78,也就是地址0x12345678的低端地址,又称小端地址。0x56对应大写字符V,0x34对应数字4,而0x12则是不可显示字符,由此证明本机是小端存储方式。
图13-8 演示小端地址存储方式示意图
可以通过图13-8中的下拉框Context选择显示内容。如图13-9所示,mainCRTStartup显示汇编代码。也可以直接用Windows菜单里在c文件和Disassembly之间选择。
图13-10是单步运行汇编程序示意图。
图13-9 Windows菜单c文件和Disassembly菜单项
图13-10 单步运行汇编程序示意图