首页 服务器 编程 必备知识 搜索引擎 圩日手册
站内搜索
最近浏览
推荐文章
热文排行

第二章 编程环境


2.1 CB界面

2.2 Win 版 Hello World

  2.2.1 一个空白工程

  2.2.2 最简单的Hello World工程

2.3 DOS 版 Hello World

  2.3.1 一个空白的控制台工程  

  2.3.2 用控制台输出“Hello world”

2.4 简单程序调试

  2.4.1 编译期错误与运行期错误

  2.4.2 学会使用帮助文档

 

在第一章,我们从一较高的高度上谈论——是的,我们只是在“谈论”计算机语言。直到最后一节,我们才相对具体地说到了编程工具。这就好比是和一个初识的女孩子海阔天空地聊了一番国际国内形势后,临走时我们问了她一句:“你有e-mail吗?”

2.1 CB界面

启动Borland C++ Builder 后,你会发现它的窗口和我们常见的一体化窗口的应用程序有所不同,CB的各子窗口并没有集成在一个主应用窗口中,而是分散为独立的子窗口。

 


(笔者的桌面分辨率为1024*728,但为了不让图的尺寸太大,我特意将各窗口拉得很小)

如果你打开CB后出现在界面和上图有所不同,可以通过File菜单,再选New Application,建一新的工程,则上图标注的2到4的窗口应该出现。如果仍然有缺,请用鼠标点上图的标注为1所示窗口的标题栏(以确保为活动状态),然后反复按F11,F12,可以在以上窗口来回切换。

下面我们来了解这四个窗口:

标注为1的窗口:这是我们比较熟悉的应用程序主窗口,虽然它看上去是一个长条,不过其上有主菜单(MainMenu),工具栏(Toolbar),和别的软件一样。不一样的是这一“长条”的右下部分的多页式工具条。事实上它并不是寻常意义上的工具条,因为其上的每一工具按钮并不提供执行某一命令的功能。我们称它为控件栏。控件是CB提供的了先进的编程思想的体现之一,本章后面我们会初步学习如何使用控件。

标注为2的窗口:相信你一眼就可以看出这是一个文件编辑的窗口。我们称之为代码编辑窗口,或简称为代码窗口。由名及义,这是我们写程序代码的地方

标注为3的窗口称它为C++ Builder软件的窗口并不妥当。事实上,它是我们自已要写的软件的窗口。Windows操作系统的应用软件,譬如Word2000,譬如WPS Office,或者简单如画笔,记事本,总是会有一或多个窗口。这是Windows应用软件的典型特征(Windows操作系统也因此称为Windows)。尽管也可以写没有窗口的应用程序,但大多数情况下我们的程序至少需要一个窗口,所以CB在创建新工程时,总是默认为我们生成一个主窗口,这就是标注为3的窗口——在程序运行前,我们称它为设计表单(Form),在程序运行之后,它就是我们程序的窗口。我们的程序需要有几个不同的窗口,就可在设计期间生成同样多个类似标注为3的设计表单。

(我对”表单”这个词总是无法产生具体的概念,可是不仅C++ Builder,还有Delphi—CB的“姐姐”,以及Visual Basic——微软的得意之作,包括.net计划中的C#等快速应用程序设计系统,都使用Form这个词来称呼设计期间的窗口。所以我还是统一口径叫表单。但不管怎样,如果你在我的课程中偶尔发现设计窗口这样的说法,不用猜测,你尽管认定我就是在说表单。一个原则:只在设计期间,我们才有可能称它为表单,当窗口运行了,那就是窗口了,我们从不叫一个运行着的窗口为表单)。

标注为4的窗口,标题写着“Object Inspector”直译对象检视器。事实上CB在调试程序时还有一个“Debug Inspector”,我倒觉得让后者叫前者的名字更合适。因为这里Object,也就对象,可不是我们以前说过面向对象的对象。它其实是用来查看,设置当前放在设计表单上的某个/些控件的属性值和事件值的工具。后面我们会用到它,控件,也称组件——但有些CB的书区分这两者,认为前者是后者的某一特定子集——就是窗口1右下的控件栏上的控件,至于控件的属性,稍后我们使用时,你就会了解。为了直观,我决定称4号窗口为控件属性检视器,或者属性检视器,或者属性窗口,总之离不了属性二字。属性检视器有两页:Properties(属性)和Events(事件)。

参照左边的图,这里顺便再统一一下口径,如图中Properties和Events;我们称它为多页(Properties为第一页,Events为第二页)。

关于分散窗口(苹果机早期的应用程序风格)的得失,我们不想在此讨论。需要说明的是,CB的的各常用子窗口都提供Dockable,因此如果你喜欢集成式的窗口,大可通过鼠标拖拖放放来定制自已的集成窗口。

Dockable是指:拖动窗口A,当经由窗口B的某一边缘地带时,窗口A可以成为窗口B上的子窗口而停靠在窗口B的某一角落。在CB里,不仅角落可以停靠,当位置为窗口B的中心时,窗口B还能以多页的方式加入窗口B。

大多数软件或许会在退出时保存住最后的窗口位置大小等设置,CB则提供你随时保存,调用各套桌面设置,比如编写代码时的桌面,调试时的桌面等。

以下就是笔者常用的,用于编写代码时CB桌面设置之一,它被我存盘为“PowerEditDsk”:



这套桌面集成了类专家(ClassExplorer),工程管理(Project Manager)及消息窗口,任务列表(To-Do List)等窗口于代码编辑窗口内。

鉴于如果各位的桌面设置不统一会造成课程讲解上的一些困难,另外还有一个不是理由的理由:CB有关桌面的设置有烦人的BUG,所以我们的课程使用CB默认的桌面设置,也是文前标有1、2、3、4的那张图中所示的窗口位置。 

2.2 Win 版Hello,World

编写自已的第一个程序,并且用字幕打出“世界你好!”——这是“很早很早”以前一本C程序教材的作者的发明——后来据说成了经典……不过很多人说这太过时了。不管怎样,我认为这作为我们初次使用CB的教学例子仍然很合适。

很多人可能感到有点突然。当CB慢吞吞启动后,一堆界面元素无论如何都让人感到这不是一个轻量级的人物;我们什么编程基础都还没有掌握,能驾驭好这个巨人吗?其实这就是CB的强大所在:具有高度的弹性,你可以用它编写很小的程序,也可以集合数十个程序员,用它编写大型软件。

牛刀小试开始。

2.2.1 一个空白工程

这是Windows的天下,尽管在《白话C++》的学习中,Windows编程并非重点,但我们还是选择了Windows作为我们认识CB的起点。

从主菜单中选择 File | New Application

(约定:在谈菜单命令时我们约定用这种格式:File | New Application 表示如上图的实际操作。)

执行 New Application之后,CB为我们新一个空白工程。所谓空白工程是指:绝大都数Windows程序所共同拥有的,必须的一个框架。再说白点,就是你每写一个新程序,都需要的一堆完全一样的代码,也就是说在多数情况,这是一步机械的工作。既然是“机械”的工作,当然由机器来完成最合适。

很多年前,笔者VC和BC都未流行的时,做了一个月“机械工”后,和许多那时的程序员一样,笔者很快尝试自已对这部分的代码进行封装。后来笔者又建议单位购买一套中国人写的窗口对象类库;再后来,笔者可始用BC,用VC,至今天,对于大家能有机会直接使用堪称最好封装的VCL学习编程,笔者能说的一句话就是:珍惜你的机会,珍惜你的20元钱。

空白工程带有一个名为“Form1”的表单(上一节图中标有“3”的窗口)。这就是程序运行时的主窗口。验证一下你就能明白:

请选菜单:Run | Run 或者按 F9 键。空白工程——当然也是一个完整的工程——被编译成程序,最后自动运行,出现一个标题为“Form1”的窗口。怎么和设计时的那个表单一模一样呢?当然,所见即所得嘛。不一样的地方也有——设计表单上有一些用于定位的小点,而运行后的窗口没有这些。

左图为表单,右图为窗口,表单(Form)指设计时的窗口,窗口(Window)指运行时的表单。

关闭该窗口,继续我们的 Hello,World的工作。

2.2.2 最简单的Hello World工程

请从C++ Builder的主窗口(上一节中标有“1”的窗口)右下部的控件栏中找到如图所示的Label控件,同时记住:Label 控件在Standard 页中。点击代表该控件的图标按钮:

(图中画有字母“A”的图标按钮即为Label,这个控件用来显示一些简单的文字内容。)鼠标摁下该按钮后(按下后按钮的形状如上图),将鼠标挪取表单Form1上随便位置点左键,一个Labe1控件被放在表单上:

用鼠标再点一下Label1,确保它为如上图中的选中状态(带有八个黑点块)。我们要通过修改属性,让它显示为“Hello,World”。

主菜单:View | Object Inspector (或者按F11键),出现Object Inspector窗口,也就是上一节中标有“4”的窗口,我们称为控件属性检视器,通过它,我们可检查并设置当前选中的控件的属性(包括事件)。 由于刚才选中了Label(如果不是,请重复用鼠标再点一下表单上的Label1)。所以Object Inspector 窗口的上部应显示如下:

上面的 Label:TLabel表示当前属性窗口显示的是 Label1的属性。同时我们注意下在的Caption属性为Label1,(注意,Name的属性也为Label1,千万别混了)。Caption意为“标题”,它决定一个Label显示的内容。你应该很明白怎么做了,在图中所示的Caption属性右边的编辑框内,将Label1改为 Hello,World。眼尖的学员一定发现,在改的同时,表单上的Labe1l如我们所愿,显示为“Hello,World”了。笔者我眼力不钝,但还是没有看到结果,原因是一个有一个窗口挡住了Form1。按一下F2,Form1跳到前面。

再按 F9,只见屏幕一闪,第一个我们参与设计的程序闪亮登场!

很好,我们已经向这个世界打声招呼。工作似乎有点成果。我们插播一段关于如何存盘的说明。 在CB中保存程序,总体上和在字处理里保存一个文档是一样的操作,比如你一般都要给新文档命名,并且找到一个合适位置保存。这里讲的是特别之处。

其一、建议大家为本课程中所讲的例子程序准备一个统一的文件夹,然后以这个文件夹为父文件夹,再为每一个例子各建一个子文件夹(除非是教程中特别指出需要将两个例子工程放于一处)。

其二、在字处理中(如MS Word),一个文档就是一个文档,而在CB的程序工程中,一个工程除了工程自身的文件以外,还包含其它配套文件。这些文件中,有些可以在保存其它文件时自动保存,现在需要我们手工保存的是工程文件和代码文件。

保存文件是相当频繁的事,我们几乎不用菜单,而总是使用快捷工具按钮(Toolbar)或者键盘,尤其是后者。这里我只讲一个按钮: 。这个有一叠软盘的图标表示Save All(保存全部),现在请点它(或按Ctrl + Shift +S)。将弹出两次的存盘对话框,第一次要求存盘的是代码文件,CB默认的文件名为Unit1;我就采用了这个默认名,必竟这只是一个小小的工程。随后是工程文件要求存盘,我一样采用了默认的Project2.bpr的名字。(正因为我们经常图省事,直接使用默认名,所以如果不将不同的工程存在各自的文件夹内,重名的文件名就将令事情很糟糕。) 最后是一些提醒:提醒一:CB默认的存盘位置是在其安装目录下的Projects文件夹。建议不要采用它,而是自已在外面新创建一个文件夹。提醒二:当程序复杂时,程序运行甚至编译时就有可能造成死机。所以在写程序时常常存盘是一种非常良好且必要的习惯。

除了这些,存盘是件再熟悉不过的事了,在File菜单下还有不少和存盘有关的命令。有空大家自个儿看看。

2.3 DOS 版 Hello,World

我们可以——并且往往是忍不住就将时间花在——把Windows版本的Hello Word的工程做得很漂亮。不过现在不是时候。在本部教程内,我们要集中全部精力,扎扎实实地打下C++ 语言的基础。这是以后我们深入学习任何编程要点,无论是Windows编程还是你想学Linux编程,也无论我们今后在实际工作中侧重于通讯或数据库或工控;甚至无论我们以后是否用C++这门语言编程——只要有C++根基,你就会比别人更容易掌握各种编程新知。

传言也并非都是假的。关于C++晦涩难懂之类的传言便很现实。另一方面,Windows编程的重点几乎全部都在于如何和Windows操作系统打交道,而和语言本身关系——它要求你有很好的C语言基础。出于这样的考虑及实际运行中遇到的困难,笔者放弃曾有的,“以语言为中心,同时学会Windows编程基础”的理想。 写DOS风格的程序想起来是令人沮丧的——没有华丽的窗口界面,也不再使用那些功能强大的控件。但正因为DOS程序的朴素,它可以使我们在更好地将重心放在C++语言本身。等到学习第二部教程时,我们才有足够的底气对Windows世界说一声:我来了!

2.3.1 一个空白的控制台工程

如果你的CB停留在前面Windows版Hello World工程中。确保退出Hello World的窗口。然后选主菜单:File | Close All。关闭Windows版Hello World工程。

菜单:File | New,出现一个 New Items对话框,等待我们选择要新建什么。

默认的选中项是图中 New页内的第一个:Application。如果选它,确认后的工程就是上一节我们创建的空的工程。但现在我们要建立一个DOS风格的程序。请选上图加有红圈的 Console Wizard (控制台程序向导)。 确认后出现向导的第一步:

请您确认将对话框中的相关选项设置成和上一图一致。然后点OK。

没有表单,只有代码编辑框窗口(第一节的“2”号窗口)内中代码为:
//---------------------------------------------------------------------------

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused

int main(int argc, char* argv[])

{

return 0;

}

//---------------------------------------------------------------------------

这是C语言的主函数,或者称为入口函数。程序从这个地方作为起来开始执行。以后会有更多讲解。同样,这也是一个程序框架,一个空白的DOS程序框架。让我们选菜单中Run | Run或直接按F9键,看看结果和前面的Windows空白程序会有什么不同?

眼前出现一个黑色的窗口,然后就一晃而过回到了C++ Builder的界面。 黑色的窗口,在不同版本的Windows中有不同的叫法和不同的实现机制,但都是Windows操作系统兼容DOS的方式。这种DOS方式在术语上称为“控制台/ console”。如果你不明白什么是DOS,请通过其它途径另外学习。

2.3.2 用控制台输出“Hello world”

我们需要加入三行代码才能实现DOS版的Hello World。以下黑体部分为你需要在代码中加入的内容:

(约定:在代码中使用黑体,用来表示您应该输入的部分)

//---------------------------------------------------------------------------

#include <stdio.h>

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused

int main(int argc, char* argv[])

{

printf("Hello,world!");

getchar();

return 0;

}

//---------------------------------------------------------------------------

这是一个很短的程序,我们稍微做点解说。

如果是一个大程序,代码一多,自已都会看晕,所以就需要在代码加一些注释,用以解说某行或某段代码的用途,或者用以让代码显得清晰。C++中,常用双斜杠 //一直到该行结束的内容来代表注释。上面的代码中,有三行:

//---------------------------------------------------------------------------

这正是用来从视觉上分隔代码的注释。注释对程序的运行没有影响,只用来给人看。当编译器编译进,它会过滤掉到所有注释内容。

#pragma hdrstop 和 #pragma argsused 两行为编译预处理命令,当编译器在编译本段代码,预处理命令会影响编译的某些行为。

#include <stdio.h> 是我们新加的一行。stdio.h 是一个文件的名字,扩展名是.h,h 是 head的意思,所以被称为头文件。这个文件在哪里呢?在你的机器里,在C++ Builder安装后的文件夹内的某个子文件夹内。在那个文件夹内,C++ Builder为我们提供了上千个头文件。头文件起什么作用呢?我们做个比喻,设想你家很富,但不幸四周的邻居都穷。今天李四推门而入,四下搜索一番,借走一把钳子,明天张三不请自来,抬走一台电视……天天有人直接进入你家,这显示是危险的。于是你在门口贴了各式清单,其一为五金工具,其二为家用电器清单……当别人需要某种东西时,先从清单上找一找是否存在,如果有,则在清单上作个登记……

Borland C++ Builder为我们提供了函数库(RTL /runtime library),类库(VCL);而Windows操作系统(Windows用C写成),则向我们提供了API函数库;库“储存”大量实用的解决各种问题,实现各种功能的“工具”,它们都通过头文件列出清单。

当我们写上#include <stdio.h> 这一行时,我们是在向编译器说明:本文件中的程序需要用到 stdio.h 头文件中所列的某些函数。include正是包含之意。

printf("Hello,world!");

getchar();

现在看这两句。printft和getchar正是两个在stdio.h中列出的函数。如果没有#include <stdio.h>这一行,编译器便会报错说不认识这两个符号。换句话说:include语句让编译知道我们要用的库函数在哪一个库里。我们会在下一节“简单程序调试”中做相应试验。

print 是打印之意,而f 则为 format,二者结合意为“有格式地打印”。我们的Hello World不需要任何格式。至于getchar,从字面上理解是“得到字符”?事实上就是程序会在此处停下来,等待用户输入字符,直到输入一个回车符,程序继续执行。在我们的这个程序里,继续执行的结果是碰上这一行:

return 0;

return是返回。当主函数main返回时,整个程序就结束了。所以,要这个getchar()的目的很明显:让程序在结束之前可以等我们一下(因为我们需要看一眼输出的“Hello World”)。

printf是输出(output)内容,而getchar()则是等待你输入,从这一点看,我们也可以理解前面include的为什么是 stdio.h了:std是英文标准的前三个字符,而I和O分别是input和output的首字母。

说了很长,但程序运行结果却很简单,这是按F9后的运行结果:

按回车,结束。结束后,别忘了保存我们的第二个程序。

2.4 简单程序调试

2.4.1 编译期错误与运行期错误

如果我在上面的程序输出时,打出的字幕不是“Hello,world”,而是“Hello,word”。你一定会说“哎,哥们,程序错了!”。于是,我就要去代码中查找有关输出的那一句,一看,哟,真少写了一个‘l’。将这一错改正,重新运行,检查结果。

这就是一个调试过程,发现错误;查找出错原因;改正;再运行。当然,由于很多时候我们也不是非要等到发现错误了才去检查,有时我们会主动一步步去事先主动检查是否有错。必竟BUG总是常见的。 程序错误(BUG)表现上各式各样,但若是从其“发作”的时间上分,则可分为“编译期错误”和“运行期错误”。如上面说的错误,属于后者,因为它对编译过程并不产生什么阻碍,编译可以顺得通过。错误在运行中表现出来。(按时间分还有一种为“链接期错误”,这里不说)

我们来故意制造一个编译期的BUG。

这是上一节的代码:

int main(int argc, char* argv[])

{

printf("Hello,world!");

getchar();

return 0;

}

现在我们故意将最后一句代码: return 0; 行末的分号删除,结果为:

int main(int argc, char* argv[])

{

printf("Hello,world!");

getchar();

return 0

}

(约定:我们用粗斜体表示修改过的代码)

现在按F9,程序并没有跑起来。但在代码编器窗口下面,出现一消息框(如果你没有发现,请在代码窗口中点鼠标右键,将出现右键菜单,选:Message View)

编译过程是一个相当复杂的过程,在编译之前,代码会被做很多格式上的转换,另一边,人写代码出错的原因也五花八门,所以,想让编译器为判断到底你犯了什么错事实上是很难的。但CB的编译出错消息竭尽全力让我们找到出错原因:

[C++ Error]: 错误类型。这是在告诉我们,这是一个C++语言语法方面的错误。编译器说对了,因为我们少写一个分号,确实是犯了语法错误。

Unit.cpp(13):错误位置。说是在Unit.cpp这个文件内的第13行。文件显然是说对了,但行数却稍有偏差,少了分号的那行其实是第12行。(从状态栏可以看到当前光标位置的行列数。

E2378:错误编号。CB对各错误消息加进行了编号。

Return statement missing; 错误消息。很好,这个消息100%正确:return 语句丢了分号。

并不是每回都能幸运得到这样准确的错误报告消息。比如同样是去掉分号,但这回把return 0那一句的分号补上,去掉它

printf(“Hello world!”)这一行的分号,编译出错消息是这样:

错误消息说我们调用了一个“非函数”,为什么呢?答案是因为没有了分号,编译将两句连成一句:printf(

“Helo,world!”)getchar();这样,它就把printf(“Helo,world!”)getchar整个儿认为一个是一个函数名,于是就不认识它了。

下面我们做一个实验,结果报错也同样为“Call of nonfunction”,但原因不是因为我们写错了函数名,而是因为我们使用了库函数,但没有通过include语句来告诉编译器:这些函数在哪个库里。

//---------------------------------------------------------------------------

//#include <stdio.h>

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused

int main(int argc, char* argv[])

{

printf("Hello,world!");

getchar();

return 0;

}

//---------------------------------------------------------------------------

代码中,我们故意有 // 将#include <stdio.h> 从一行代码摇身一变成为一行注释。前面说过注释是仅给人看的,编译看不到这一行,相当于你删除了这一行。现在编译这一行,错误如下:

两行同样类型的错误消息。编译一下子不认识printf和getchar两个函数了。

2.4.2 学会使用帮助文档

经过上一节,同学可能会问三个问题:

第一,“老师,你怎么知道有printf和getchar这个两个函数呢?”

回答:两个途径:常用的函数会在课程里讲到。其它函数则根据需要在各上文档中查找”。

第二,你怎么会知道printf是用来输出而getchar则可以用于等待输入?

回答和上面一致,从课程和文档中获得。

第三,就算知道了printf这个函数,我又怎么才能知道它在 stdio这个头文件对应的库里?

回答还是一样。

学会使用文档看来很重要。文档有多种,比如有专门的函数大全之类的书,不过现在的文档是帮助文档。初学者在调试程序时,很多人由于英文不佳,于是根本不去动帮助文档。其实当你带些具体的目的去看帮助文档,你会发现就算英文不好,你可以从中获得帮助,解决大部分程序问题。

我们用一节的那个BUG来说明问题。假如你用了printf和getchar这两个函数,但你不知它们包含在哪个库里(也就是说你不知道在#include 之后应该写”stdio.h”)。

菜单:Help | C++ Builder Help

出现Windows标准的帮助索引窗口,我们在索引内键入:printf。

如此,我们找到了有关printf 的帮助:

看,红圈内的内容清楚地说明了什么?

(提高英语水平对学习编程的帮助是很大的。如果你需要学习英语,就不妨听我做一句广告:

英语学万,开口如有——点击此处查看我们的最新英语学习产品《句神英语2002》介绍

在广告的喧哗声中,我们结束了第二章的学习。

[wangjy17908]
添加时间:2008-04-12
版权所有(C)2005-2015