C语言编程要点---第18章程序的编写和编译

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

C语言编程要点---第18章程序的编写和编译第18章程序的编写和编译本章讲述在编译程序时可以使用的一些技术。在本章中,你将学到专业C程序员在日常编程中所使用的一些技巧。你将会发现,无论是对小项目还是大项目,把源代码分解成几个文件都是很有益处的。在生成函数库时,这一点更为重要。你还将学到可以使用的各种存储模式以及怎样为不同的项目选择不同的存储模式。如果你的程序是由几个源文件组成的,那么你可以通过一个叫MAKE的工具来管理你的项目(project)。你还将学到“.COM文件和.EXE文件的区别以及使用“.COM”文件的一个好处。此外,你还将学到用来解决一个典型的DOS问题的一些技巧,这个问题就是“没有足够的内存来运行DOS程序”。本章还讨论了扩展内存、扩充内存、磁盘交换区、覆盖管理程序和DOS扩展程序的用法,提出了解决RAM阻塞”这一问题的多种方法,你可以从中选择一种最合适的方法18.1.程序是应该写成一个源文件还是多个源文件?如果你的程序确实很小又很紧凑,那么当然应该把所有的源代码写在一个“.C”文件中。然而,如果你发现自己编写了许多函数(特别是通用函数),那么你就应该把程序分解成几个源文件(也叫做模块)。把一个程序分解成几个源文件的过程叫做模块化程序设计(modularprogramming)。模块化程序设计技术提倡用几个不同的结构紧凑的模块一起组成一个完整的程序。例如,如果一个程序中有几种实用函数、屏幕函数和数据库函数,你就可以把这些函数分别放在三个源文件中,分别组成实用模块、屏幕模块和数据库模块。把函数放在不同的文件中后,你就可以很方便地在其它程序中重复使用那些通用函数。如果你有一些函数还要供其它程序员使用,那么你可以生成一个与别人共享的函数库(见18.9)。你永远不必担心模块数目“太多”——只要你认为合适,你可以生成很多个模块。一条好的原则就是保持模块的紧凑性.即在同一个源文件中只包含那些在逻辑上与其相关的函数。如果你发现自己把几个没有关系的函数放在了同一个源文件中,那么最好停下来检查一下程序的源代码结构,并且对模块做一下逻辑上的分解。例如,如果要建立一个通信管理数据库,你可能需要有这样一个模块结构:---------------------------------------------------------模块名内容---------------------------------------------------------Main.cmaln()函数Screen.c屏幕管理函数Menus.c菜单管理函数Database.c数据库管理函数Utility.c通用功能函数Contact.c通信处理函数Import.c记录输入函数Export.c记录输出函数Help.c联机帮助支持函数----------------------------------------------------------请参见:18.10如果一个程序包含多个源文件,怎样使它们都能正常工作?18.2.各种存储模式之间有什么区别?DOS用一种段地址结构来编址计算机的内存,每一个物理内存位置都有一个可通过段地址一偏移量的方式来访问的相关地址。为了支持这种段地址结构,大多数C编译程序都允许你用以下6种存储模式来创建程序:-----------------------------------------------------------------------存储模式限制所用指针-----------------------------------------------------------------------Tiny(微)代码、数据和栈一64KBNearSmall(小)代码一64KBNear数据和栈一64KBNearMedium(中)代码一1MBFar数据和栈一64KBNearCompact(紧缩)代码一64KBNear数据和栈一1MBFarLarge(大)代码一1MBFar数据和栈一1MBFarHuge*(巨)代码一1MBFar数据和栈一1MBFar-----------------------------------------------------------------------*注意:在Huge存储模式下,静态数据(如数组)可以超过64KB,这在其它存储模式下都不行。Tiny存储模式的限制很严(所有的代码、数据和栈都被限制在64KB中),它通常用来生成COM文件。由于内存地址的“安排”方式的限制,Huge模式会带来显著的性能损失,因此它很少被使用。请参见:18.3最常使用的存储模式有哪些?18.4应该使用哪种存储模式?18.3.最常使用的存储模式有哪些?最常使用的存储模式有Small,Medium和Large这几种。Tiny存储模式一般只用来生成.COM文件,在现在的高性能计算机上,它已很少被使用了。Compact存储模式允许程序有很少的代码和大量的数据,在今天的商业应用环境中,它同样也不常用了。由于Huge存储模式的存储地址机制导致它的效率较低,所以它也很少被使用。一般说来,你应该根据程序的大小选用Small,Medium或Large中的一种存储模式。对一个小的实用程序来说,Small存储模式可能是最合适的,这种存储模式允许有64KB的代码和64KB数据和栈。如果程序有更大一些的数据要求,你可以使用Medium存储模式,它允许程序有多达1MB的可寻址数据空间。对于更大的程序,你应该使用Large存储模式,它允许程序有1MB的代码和1MB的数据和栈空间。如果你在编写一个Windows程序或者在使用一个32位编译程序,那么你最好使用Small存储模式,因为这样的环境并不受DOS程序的段地址结构的限制。请参见:18.2各种存储模式之间有什么区别?18.4应该使用哪种存储模式?18.4.应该使用哪种存储模式?如果要生成一个“.COM”文件,必须使用Tiny存储模式,即所有的代码、数据和栈空间都被限制在64KB中。小的实用程序普遍使用这种存储模式。相对较小的程序也可以使用Small存储模式,只不过不必把整个程序都限制在64KB中。在Small存储模式下,有64KB的代码空间和64KB的数据和栈空间。除了用于小程序外,Small存储模式还可用在Windows或32位编译程序这样的环境中,因为在这些环境中内存寻址并不受DOS中16位的限制。如果一个程序的代码量相对较大而静态数据量相对较小,你可以用Medium存储模式来创建程序。如果程序很大(需要很多模块,大量的代码和数据),那么你应该选用Large存储模式,这种存储模式常用在DOS下编写商用软件。与Small,Medium和Large存储模式相比,Compact和Huge存储模式要少用得多。Cornpact存储模式允许程序有大量的静态数据和相对较少(64KB或更少)的代码。满足这种模式的程序很少,常常是一些转移程序,它们有大量必须存到内存中的静态转移表。Huge存储模式与Large存储模式基本相同,只是Huge存储模式允许程序有超过64KB的静态数据。与Compact存储模式相似,Huge存储模式也很少被使用,这主要是因为它会带来显著的性能损失。由于Huge存储模式的执行效率较低,因此你应该避免使用这种模式,除非你确实需要超过64KB的一个数组或其它静态数据。记住,数组和其它程序结构可通过malloc()和calloc()在程序运行时进行动态分配,它们在本质上并不必须是静态的。请参见:18.2各种存储模式之间有什么区别?18.3最常使用的存储模式有哪些?18.5.怎样生成一个“.COM”文件?生成一个“.COM”文件是指用Tiny存储模式编译程序,并用特殊的连接命令产生扩展名为.COM而不是.EXE的文件。记住,如果要使一个程序成为一个“.COM”文件,那么所有的代码、数据和栈都必须限制在64KB之内。这种存储模式通常只被一些很小的程序使用,例如TSR程序和小的实用程序。每个编译程序生成“.COM”文件的方法都是不同的,你应该在编译程序手册中查找有关信息,以了解哪些编译选项或连接选项是用来生成.COM文件而不是.EXE文件的。请参见:18.6“.COM”文件有哪些地方优于“.EXE文件?18.6.“.COM”文件有哪些地方优于“.EXE”文件?一个“.COM”文件的所有代码、数据和栈都被限制在64KB之内,因此,它只能用在一些小的应用中,例如实用程序和TSR程序(终止并驻留程序)。“.COM”文件的一个明显优点就是它的装入要比“.EXE文件快得多。“.COM”文件也被称作“内存映象”文件,因为它可以直接装入内存,不需要任何“处理”。“.EXE文件中包含了由连接程序插入到其它文件头中的一些特殊的组装指令,这些指令中包括一个用来管理可执行程序的不同部分的重定位表。“.COM”文件中不包含任何这样的指令或重定位表,因为整个程序可以装入64KB的内存空间中。因此,DOS不必去分析任何组装指令,“.COM”文件的装入速度也就比.EXE文件快。“.COM”文件通常很简单,因此它们所能实现的功能也就受到限制。例如,你不能在“.COM”文件中从远程堆中分配内存。请参见:18.5怎样生成一个“.COM”文件?18.7.当一个库被连接到目标上时,库中的所有函数是否都会被加到一个.EXE文件中?不会。当启动连接程序时,它会寻找“未定义的外部函数”,也就是说,它将在每一个库文件中查找源代码文件中未定义的函数。当它找到一个未定义的外部函数后,它会引入包含该函数定义的目标代码。(obj)。不幸的是,如果这个函数是在一个包含其它函数定义的源文件中被编译的话,那么这些函数也会被包含进来,你的可执行代码中将包含一些不需要的代码。因此,将库函数放到各自的源文件中是很重要的——否则会浪费宝贵的程序空间。有些编译程序包含特殊的“精明的”连接程序,这些连接程序能查出不需要的函数并去掉它们,从而使这些函数不再进入你的程序。下面举一个例子:假设有两个源文件,分别为libfunc1.c和libfunc2.c,它们所包含的函数都要被放到一个库中。源文件libfunc1.c包含以下两个函数:voidfunc_one(){...}voidrune_two(){...}源文件libfunc2.c包含以下函数:voidfunc_three(){...}现在假设已经把这两个源文件编译到一个名为myfuncs.1ib的库中。如果一个与myfuncs.lib连接的程序要调用func_one()函数,连接程序就会在myfuncs.lib库中寻找包含func_one()函数定义的目标代码,并且把它连接进来。不幸的是,函数func_one()是在包含func_two()函数定义的同一个源文件中被编译的,因此,即使你的程序不会用到func_two(),连接程序也不得不把它连接进来。当然,这里假设func_one()中并没有包含对func_two()的调用。如果一个程序包含一个对func_three()的调用,那么只有func_othree()的目标代码会被连接进来,因为该函数是在它自己的源文件中被编译的。一般说来,你应该尽量把库函数放到各自的源文件中。这种组织方式有助于提高程序的效率,因为程序只会和那些真正需要的函数进行连接,而不会和那些不需要的函数进行连接。这种组织方式在小组开发的情况下也是很有帮助的;在小组开发中,源文件的上交和发放非常频繁,如果一个程序员要对一个包含在其自身的源文件中的函数进行维护,那么他可以集中维护这个函数;如果这个函数所在的源文件中还包含其它一些需要维护的函数,那么这些函数就无法发放给其它小组成员,因为它们包含在一个源文件中。请参见:18.8可以把多个库函数包含在同一个源文件中吗?18.9为什么要建立一个库?18.8.可以把多个库函数包含在同一个源文件中吗?在同一个源文件中,你想要定义多少个函数,就可以定义多个函数,并且可以把它们都包含到一个库中——然而,在小组开发环境中连接程序和共享源文件时,这种编程风格存在

1 / 9
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功