1.4 程序的开发周期
在Windows下,利用“记事本”(Notepad.exe)这个小软件,可以输入并编辑文字,然后保存到计算机硬盘上,如图1-2所示。保存到硬盘上的数据以文件的形式存在,如要将文件保存到“d:\”目录,在保存的时候,“记事本”软件会提示用户输入文件名和保存的路径,例如我们可以用“C.txt”作为文件名,以“d:\”作为文件路径。保存后,通过Windows的文件浏览器定位到“d:\”就可以看到文件“C.txt”。同样的,用画图小软件可以信手涂鸦,也能保存一个扩展名为bmp的文件到硬盘上,如图1-2所示。
图1-2 记事本和画图可以产生文件
可以看到,“记事本”和“画图”都可以产生出文件来。这些文件被称作“文档”。这些文档都可以被应用软件打开,它们自身是无法运行也无法展现其内容的。例如,要查看.txt文本文档的内容,可以使用“记事本”软件打开;又如,想要听.mp3音频文件的声音,可以使用mp3播放软件打开。那么如何产生一个.exe的可执行文件呢?
聪明的读者一定知道了。是的,就是通过编写某种语言的源代码,编译成功通过后,再经过连接,成功后就出现了计算机可以执行的一个.exe文件了。这就是所谓的程序。是不是只有C语言才能编制出.exe的程序来呢?当然不是的。据不完全统计,全球现存的编程语言多达2500多种,这其中大部分都可以经过编译连接,最后产生出一个.exe可执行文件来。但是基本上,它们都遵循同样的流程:编辑源代码,编译源代码,连接目标程序,最后生成一个.exe可执行文件。用C语言开发程序的流程如图1-3所示。
图1-3 开发程序的流程
1.4.1 编辑C源代码
编辑C源代码就是做如下工作:
(1)逐个输入字符,如汉字、英文、标点符号或者其他可以用键盘输入的字符。
(2)通过插入、删除、移动、复制、粘贴等方法修改已经输入的字符。
(3)将输入、修改完毕的所有字符保存到硬盘上。
一篇由汉字、英文、标点符号或者其他可以用键盘输入的字符组合的内容被称作文本。能够进行文字编辑的软件被称作编辑器。
通俗地讲,源代码就是程序员输入编写的、符合C语言语法规则的文本。如下列片段就是一段源代码:
void main(void) { printf("\nHello World!"); }
一般用扩展名.c表示其为一个C源代码文件。源代码文件简称源文件,有时候也叫作源程序。程序员的主要工作之一就是根据需求编写源代码。
编辑器的功能在很大程度上能够帮助程序员提高工作效率。只要能输入文字的文本编辑软件都可以作为源代码编辑器。如记事本软件、字处理软件Word、Ultra Edit、Edit Plus等。但是专业程序员一般都采用专业的源代码编辑器。业界鼎鼎有名的编辑工具有VI/VIM、Emacs/XEmacs等。一个好的源代码编辑器,要求具备关键字着色功能(可以用不同的颜色表示代码的不同部分)、优秀的代码跳转功能、代码自动补全功能等。虽然用最普通的记事本软件也能编辑代码,但是却十分不方便。
1.4.2 编译C源代码
编译是把C语言源代码翻译成用二进制指令表示的目标文件。注意,这里的目标文件与机器语言还有一段距离,并不是真正的机器语言,所以不能被计算机直接运行。编译着重于“译”,就是翻译。
声明 读者要注意区分编辑和编译的概念。虽然一字之差,意义却大不相同。编辑,是指对文本的修改、插入、删除等操作;而编译却是将编辑好的源代码翻译成目标文件。
编译过程由C编译系统提供的编译程序完成。编译程序简称为编译器。编译程序运行后,自动对源程序进行句法和语法检查,当发现错误时,就将错误的类型和所在的位置显示出来,以帮助用户修改源程序中的错误。用户可以再利用编辑器对源程序进行修改。修改好后,重新进行编译,直到编译通过为止。如果未发现句法和语法方面的错误,就自动形成目标代码,并对目标代码进行优化后生成目标文件。
目标程序文件的扩展名为.obj,它是目标程序的文件类型标识。不同的编译系统,或者不同版本的编译程序,它们的启动命令不同,生成的目标文件也不相同,扩展名有时候也不一定相同,当然格式也不相同,但是其作用相同。
一个C源代码文件编译后就会产生一个目标文件与之对应。一般不会出现多个源代码文件对应一个目标文件的情况。进行软件开发涉及的源代码文件个数,不会像教学C语言这样简单到只有一个源文件,而是几十、上百甚至成千上万个。所以大型软件的开发一般通过工程文件的方式来管理源代码。
请读者思考一下,为什么软件开发不直接从源代码一步到位翻译成可执行文件,而要经过编译后,再经过连接这个步骤呢?这个问题,留在后续章节再解释。当读者明白了这个问题后,也就明白了目标文件存在的意义了。
1.4.3 连接目标文件
多个源代码文件经编译后产生了对应的多个目标文件,此时还没有将其组合装配成一个可以运行的整体,因此计算机还是不能执行。连接过程是用连接程序将目标文件、第三方目标文件、C语言提供的运行时库文件连接装配成一个完整的可执行的目标程序。连接程序简称连接器。
可执行程序文件的扩展名为.exe,是可执行程序的文件类型标识。绝大部分系统生成的可执行文件的扩展名是.exe,但是在UNIX系统中,除非在编译时用户特别规定自己的文件名,否则生成的可执行文件自动确定为a.out。有的C编译系统把编译和连接放在一个命令文件中,用一条命令即可完成编译和连接任务,减少了操作步骤。
程序员开发程序,除了要编写自己的代码外,有时候会使用其他人提供的库文件。如读者要编写一个mp3播放器软件,对于mp3解码部分,因为已经有现成的第三方代码库做好了这件事情,可以直接拿这个第三方库文件来使用。这个库提供的功能可供用户的播放器软件调用。为了方便开发,C语言也有一批库函数,一般编译厂商都会提供给开发人员使用。
1.4.4 编译连接过程示例
有时候为了叙述简便,将编译连接这两个步骤,统一用“编译”一个词语代替,读者应该清楚实际是经历过了两步。例如在Visual Studio编程环境里,当用户下达build(构建)命令后,开发环境就开始编译连接工作。本节的示例没有列出源文件,源文件名是main.c,内容可以暂时不考虑,读者只关注编译、连接的步骤即可。
(1)当源代码中没有错误时,其工作过程输出如下:
------ Build started: Project: 9.1, Configuration: Debug Win32 ------ Compiling... main.c Linking... Build log was saved at "file://e:\study\C Study\9.1\Debug\BuildLog.htm" 9.1 - 0 error(s), 0 warning(s)
从这个Build的过程中,明显看出经历了“Compiling…”(编译)、“Linking…”(连接)两步。最后结果是“0 error(s),0 warning(s)”,即没有错误也没有警告。
(2)如果源代码有错误,在编译过程就会提示用户。由于没有通过编译,也就没有目标文件,所以连接也就不用进行了。一个源代码错误编译不通过的示例如下:
------ Build started: Project: 9.1, Configuration: Debug Win32 ------ Compiling... main.c e:\study\C Study\9.1\main.c(20) : error C2143: syntax error : missing ')' before '{' Build log was saved at "file://e:\study\C Study\9.1\Debug\BuildLog.htm" 9.1 - 1 error(s), 0 warning(s) ---------------------- Done ---------------------- Build: 0 succeeded, 1 failed, 0 skipped
说明 读者现在可能还不明白错误提示信息的含义,不用担心,在后面的章节中会慢慢讲到。现在读者只需要关注如果源代码有错误,会出现什么情况即可。
“e:\study\C Study\9.1\main.c(20):error C2143:syntax error:missing')'before'{'”这行输出表示,代码第20行(“( )”内表示出来的)出现错误。错误代码是C2143,具体错误是语法错误,在“{”前缺少“)”。双击错误提示可将鼠标光标定位到错误行处,可以修改源代码。
(3)有时候编译通过了,但是连接却不一定通过。如下:
------ Build started: Project: 9.1, Configuration: Debug Win32 ------ Compiling... main.c Linking... LIBCD.lib(crt0.obj) : error LNK2019: unresolved external symbol _main referenced in function _mainCRTStartup Debug/9.1.exe : fatal error LNK1120: 1 unresolved externals Build log was saved at "file://e:\study\C Study\9.1\Debug\BuildLog.htm" 9.1 - 2 error(s), 0 warning(s) ---------------------- Done ---------------------- Build: 0 succeeded, 1 failed, 0 skipped
编译main.c后没有提示信息,表示通过,产生了.obj文件。Linking提示后,表示开始进行连接。但是在连接过程中出现错误,最终没有产生.exe文件。同样,具体的连接错误原因,这里不再分析了。
1.4.5 运行程序
运行程序是指将可执行的目标程序投入运行,以获取程序处理的结果。如果程序运行结果不正确,可重新回到第一步,对程序进行编辑修改、编译和运行。与编译、连接不同的是,运行程序可以脱离语言开发环境。因为它是对一个可执行程序进行操作,与C语言本身已经没有联系,所以既可以在语言开发环境下运行,也可直接在操作系统下运行。