版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
C語言編程要點---第18章程序的編寫和編譯第18章
程序的編寫和編譯本章講述在編譯程序時可以使用的一些技術。在本章中,你將學到專業(yè)C程序員在日常編程中所使用的一些技巧。你將會發(fā)現(xiàn),無論是對小項目還是大項目,把源代碼分解成幾個文件都是很有益處的。在生成函數(shù)庫時,這一點更為重要。你還將學到可以使用的各種存儲模式以及怎樣為不同的項目選擇不同的存儲模式。如果你的程序是由幾個源文件組成的,那么你可以通過一個叫MAKE的工具來管理你的項目(project)。你還將學到“.COM"文件和".EXE"文件的區(qū)別以及使用“.COM”文件的一個好處。
此外,你還將學到用來解決一個典型的DOS問題的一些技巧,這個問題就是“沒有足夠的內(nèi)存來運行DOS程序”。本章還討論了擴展內(nèi)存、擴充內(nèi)存、磁盤交換區(qū)、覆蓋管理程序和DOS擴展程序的用法,提出了解決"RAM阻塞”這一問題的多種方法,你可以從中選擇一種最合適的方法18.1.
程序是應該寫成一個源文件還是多個源文件?
如果你的程序確實很小又很緊湊,那么當然應該把所有的源代碼寫在一個“.C”文件中。然而,如果你發(fā)現(xiàn)自己編寫了許多函數(shù)(特別是通用函數(shù)),那么你就應該把程序分解成幾個源文件(也叫做模塊)。
把一個程序分解成幾個源文件的過程叫做模塊化程序設計(modularprogramming)。模塊化程序設計技術提倡用幾個不同的結構緊湊的模塊一起組成一個完整的程序。例如,如果一個程序中有幾種實用函數(shù)、屏幕函數(shù)和數(shù)據(jù)庫函數(shù),你就可以把這些函數(shù)分別放在三個源文件中,分別組成實用模塊、屏幕模塊和數(shù)據(jù)庫模塊。
把函數(shù)放在不同的文件中后,你就可以很方便地在其它程序中重復使用那些通用函數(shù)。如果你有一些函數(shù)還要供其它程序員使用,那么你可以生成一個與別人共享的函數(shù)庫(見18.9)。
你永遠不必擔心模塊數(shù)目“太多”——只要你認為合適,你可以生成很多個模塊。一條好的原則就是保持模塊的緊湊性.即在同一個源文件中只包含那些在邏輯上與其相關的函數(shù)。如果你發(fā)現(xiàn)自己把幾個沒有關系的函數(shù)放在了同一個源文件中,那么最好停下來檢查一下程序的源代碼結構,并且對模塊做一下邏輯上的分解。例如,如果要建立一個通信管理數(shù)據(jù)庫,你可能需要有這樣一個模塊結構:---------------------------------------------------------
模塊名
內(nèi)容---------------------------------------------------------
Main.c
maln()函數(shù)
Screen.c
屏幕管理函數(shù)
Menus.c
菜單管理函數(shù)
Database.c
數(shù)據(jù)庫管理函數(shù)
Utility.c
通用功能函數(shù)
Contact.c
通信處理函數(shù)
Import.c
記錄輸入函數(shù)
Export.c
記錄輸出函數(shù)
Help.c
聯(lián)機幫助支持函數(shù)----------------------------------------------------------請參見:18.10如果一個程序包含多個源文件,怎樣使它們都能正常工作?18.2.
各種存儲模式之間有什么區(qū)別?
DOS用一種段地址結構來編址計算機的內(nèi)存,每一個物理內(nèi)存位置都有一個可通過段地址一偏移量的方式來訪問的相關地址。為了支持這種段地址結構,大多數(shù)C編譯程序都允許你用以下6種存儲模式來創(chuàng)建程序:-----------------------------------------------------------------------存儲模式
限制
所用指針-----------------------------------------------------------------------Tiny(微)
代碼、數(shù)據(jù)和棧一64KB
NearSmall(小)
代碼一64KB
Near
數(shù)據(jù)和棧一64KB
NearMedium(中)
代碼一1MB
Far
數(shù)據(jù)和棧一64KB
NearCompact(緊縮)
代碼一64KB
Near
數(shù)據(jù)和棧一1MB
FarLarge(大)
代碼一1MB
Far
數(shù)據(jù)和棧一1MB
FarHuge*(巨)
代碼一1MB
Far
數(shù)據(jù)和棧一1MB
Far-----------------------------------------------------------------------
*注意:在Huge存儲模式下,靜態(tài)數(shù)據(jù)(如數(shù)組)可以超過64KB,這在其它存儲模式下都不行。
Tiny存儲模式的限制很嚴(所有的代碼、數(shù)據(jù)和棧都被限制在64KB中),它通常用來生成"COM"文件。由于內(nèi)存地址的“安排”方式的限制,Huge模式會帶來顯著的性能損失,因此它很少被使用。
請參見:
18.3最常使用的存儲模式有哪些?
18.4應該使用哪種存儲模式?18.3.
最常使用的存儲模式有哪些?
最常使用的存儲模式有Small,Medium和Large這幾種。Tiny存儲模式一般只用來生成".COM"文件,在現(xiàn)在的高性能計算機上,它已很少被使用了。Compact存儲模式允許程序有很少的代碼和大量的數(shù)據(jù),在今天的商業(yè)應用環(huán)境中,它同樣也不常用了。由于Huge存儲模式的存儲地址機制導致它的效率較低,所以它也很少被使用。
一般說來,你應該根據(jù)程序的大小選用Small,Medium或Large中的一種存儲模式。對一個小的實用程序來說,Small存儲模式可能是最合適的,這種存儲模式允許有64KB的代碼和64KB數(shù)據(jù)和棧。如果程序有更大一些的數(shù)據(jù)要求,你可以使用Medium存儲模式,它允許程序有多達1MB的可尋址數(shù)據(jù)空間。對于更大的程序,你應該使用Large存儲模式,它允許程序有1MB的代碼和1MB的數(shù)據(jù)和棧空間。
如果你在編寫一個Windows程序或者在使用一個32位編譯程序,那么你最好使用Small存儲模式,因為這樣的環(huán)境并不受DOS程序的段地址結構的限制。
請參見:
18.2各種存儲模式之間有什么區(qū)別?
18.4應該使用哪種存儲模式?18.4.
應該使用哪種存儲模式?
如果要生成一個“.COM”文件,必須使用Tiny存儲模式,即所有的代碼、數(shù)據(jù)和??臻g都被限制在64KB中。小的實用程序普遍使用這種存儲模式。相對較小的程序也可以使用Small存儲模式,只不過不必把整個程序都限制在64KB中。在Small存儲模式下,有64KB的代碼空間和64KB的數(shù)據(jù)和棧空間。除了用于小程序外,Small存儲模式還可用在Windows或32位編譯程序這樣的環(huán)境中,因為在這些環(huán)境中內(nèi)存尋址并不受DOS中16位的限制。
如果一個程序的代碼量相對較大而靜態(tài)數(shù)據(jù)量相對較小,你可以用Medium存儲模式來創(chuàng)建程序。如果程序很大(需要很多模塊,大量的代碼和數(shù)據(jù)),那么你應該選用Large存儲模式,這種存儲模式常用在DOS下編寫商用軟件。
與Small,Medium和Large存儲模式相比,Compact和Huge存儲模式要少用得多。Cornpact存儲模式允許程序有大量的靜態(tài)數(shù)據(jù)和相對較少(64KB或更少)的代碼。滿足這種模式的程序很少,常常是一些轉移程序,它們有大量必須存到內(nèi)存中的靜態(tài)轉移表。Huge存儲模式與Large存儲模式基本相同,只是Huge存儲模式允許程序有超過64KB的靜態(tài)數(shù)據(jù)。與Compact存儲模式相似,Huge存儲模式也很少被使用,這主要是因為它會帶來顯著的性能損失。由于Huge存儲模式的執(zhí)行效率較低,因此你應該避免使用這種模式,除非你確實需要超過64KB的一個數(shù)組或其它靜態(tài)數(shù)據(jù)。記住,數(shù)組和其它程序結構可通過malloc()和calloc()在程序運行時進行動態(tài)分配,它們在本質(zhì)上并不必須是靜態(tài)的。
請參見:
18.2各種存儲模式之間有什么區(qū)別?
18.3最常使用的存儲模式有哪些?18.5.
怎樣生成一個“.COM”文件?
生成一個“.COM”文件是指用Tiny存儲模式編譯程序,并用特殊的連接命令產(chǎn)生擴展名為".COM"而不是".EXE"的文件。記住,如果要使一個程序成為一個“.COM”文件,那么所有的代碼、數(shù)據(jù)和棧都必須限制在64KB之內(nèi)。這種存儲模式通常只被一些很小的程序使用,例如TSR程序和小的實用程序。
每個編譯程序生成“.COM”文件的方法都是不同的,你應該在編譯程序手冊中查找有關信息,以了解哪些編譯選項或連接選項是用來生成".COM"文件而不是".EXE"文件的。
請參見:
18.6“.COM”文件有哪些地方優(yōu)于“.EXE"文件?18.6.
“.COM”文件有哪些地方優(yōu)于“.EXE”文件?
一個“.COM”文件的所有代碼、數(shù)據(jù)和棧都被限制在64KB之內(nèi),因此,它只能用在一些小的應用中,例如實用程序和TSR程序(終止并駐留程序)?!埃瓹OM”文件的一個明顯優(yōu)點就是它的裝入要比“.EXE"文件快得多。
“.COM”文件也被稱作“內(nèi)存映象”文件,因為它可以直接裝入內(nèi)存,不需要任何“處理”?!埃瓻XE"文件中包含了由連接程序插入到其它文件頭中的一些特殊的組裝指令,這些指令中包括一個用來管理可執(zhí)行程序的不同部分的重定位表?!埃瓹OM”文件中不包含任何這樣的指令或重定位表,因為整個程序可以裝入64KB的內(nèi)存空間中。因此,DOS不必去分析任何組裝指令,“.COM”文件的裝入速度也就比".EXE"文件快。
“.COM”文件通常很簡單,因此它們所能實現(xiàn)的功能也就受到限制。例如,你不能在“.COM”文件中從遠程堆中分配內(nèi)存。
請參見:
18.5怎樣生成一個“.COM”文件?18.7.
當一個庫被連接到目標上時,庫中的所有函數(shù)是否都會被加到一個".EXE"文件中?
不會。當啟動連接程序時,它會尋找“未定義的外部函數(shù)”,也就是說,它將在每一個庫文件中查找源代碼文件中未定義的函數(shù)。當它找到一個未定義的外部函數(shù)后,它會引入包含該函數(shù)定義的目標代碼。(obj)。不幸的是,如果這個函數(shù)是在一個包含其它函數(shù)定義的源文件中被編譯的話,那么這些函數(shù)也會被包含進來,你的可執(zhí)行代碼中將包含一些不需要的代碼。因此,將庫函數(shù)放到各自的源文件中是很重要的——否則會浪費寶貴的程序空間。有些編譯程序包含特殊的“精明的”連接程序,這些連接程序能查出不需要的函數(shù)并去掉它們,從而使這些函數(shù)不再進入你的程序。
下面舉一個例子:假設有兩個源文件,分別為libfunc1.c和libfunc2.c,它們所包含的函數(shù)都要被放到一個庫中。
源文件libfunc1.c包含以下兩個函數(shù):
voidfunc_one()
{
...
}
voidrune_two()
{
...
}
源文件libfunc2.c包含以下函數(shù):
voidfunc_three()
{
...
}
現(xiàn)在假設已經(jīng)把這兩個源文件編譯到一個名為myfuncs.1ib的庫中。如果一個與myfuncs.lib連接的程序要調(diào)用func_one()函數(shù),連接程序就會在myfuncs.lib庫中尋找包含func_one()函數(shù)定義的目標代碼,并且把它連接進來。不幸的是,函數(shù)func_one()是在包含func_two()函數(shù)定義的同一個源文件中被編譯的,因此,即使你的程序不會用到func_two(),連接程序也不得不把它連接進來。當然,這里假設func_one()中并沒有包含對func_two()的調(diào)用。如果一個程序包含一個對func_three()的調(diào)用,那么只有func_othree()的目標代碼會被連接進來,因為該函數(shù)是在它自己的源文件中被編譯的。
一般說來,你應該盡量把庫函數(shù)放到各自的源文件中。這種組織方式有助于提高程序的效率,因為程序只會和那些真正需要的函數(shù)進行連接,而不會和那些不需要的函數(shù)進行連接。這種組織方式在小組開發(fā)的情況下也是很有幫助的;在小組開發(fā)中,源文件的上交和發(fā)放非常頻繁,如果一個程序員要對一個包含在其自身的源文件中的函數(shù)進行維護,那么他可以集中維護這個函數(shù);如果這個函數(shù)所在的源文件中還包含其它一些需要維護的函數(shù),那么這些函數(shù)就無法發(fā)放給其它小組成員,因為它們包含在一個源文件中。
請參見:
18.8可以把多個庫函數(shù)包含在同一個源文件中嗎?
18.9為什么要建立一個庫?18.8.
可以把多個庫函數(shù)包含在同一個源文件中嗎?
在同一個源文件中,你想要定義多少個函數(shù),就可以定義多個函數(shù),并且可以把它們都包含到一個庫中——然而,在小組開發(fā)環(huán)境中連接程序和共享源文件時,這種編程風格存在著嚴重的缺陷。
當你在一個源文件中包含多個庫函數(shù)時,這些函數(shù)會被編譯到同一個目標(.obj)文件中。當連接程序要把其中的一個函數(shù)連接到程序中去時,目標文件中的所有函數(shù)都將被連接進來---不管程序是否用到它們。如果這些函數(shù)是無關的(在它們的定義中沒有相互調(diào)用),那么會因為把不需要的代碼連接進來而浪費寶貴的程序空間,見18.7中的例子。這就是要把庫函數(shù)放到各自的源文件中的原因之一。
另一個原因是為了在小組開發(fā)環(huán)境下便于進行代碼共享。使用獨立的源文件能使小組程序員上交和收回單獨一個函數(shù),而不必先鎖住源文件中的一些函數(shù),然后才能修改源文件中的其它函數(shù)。
請參見:
18.7當一個庫被連接到目標上時,庫中的所有函數(shù)是否都會被加到一個“.EXE"文件中?
18.9為什么要建立一個庫?18.9.
為什么要建立一個庫?
建立一個數(shù)據(jù)庫是為了把可重復使用的函數(shù)放在一起,供其它程序員和程序共享。例如,你的幾個程序可能都會用到一些通用的功能函數(shù),你不必在每個程序中都復制這些源代碼,而只需把這些函數(shù)集中到一個函數(shù)庫中,然后用連接程序把它們連接到你的程序中去。這種方法有利于程序的維護,因為你可以在一個集中的地方而不是幾個分散的地方維護你的函數(shù)。
如果你在小組環(huán)境中工作,那么你應該把你的可重復使用的函數(shù)放到一個庫中,這樣其它小組成員就可以把你的函數(shù)連接到他們的程序中去,從而節(jié)省了他們復制或從頭開始寫這些函數(shù)的時間。此外,在一個包含幾個模塊的大項目中,可以把那些自始至終都要用到的“框架”支持函數(shù)包含到一個庫中。
編譯程序中包含一個庫管理器(通常叫做LIB.EXE或其它類似的名字),可用來在函數(shù)庫中增減目標代碼模塊(.obj)。有些編譯程序允許你在它們的集成開發(fā)環(huán)境中維護你的庫,而不必人為地啟動庫管理器。無論如何,你都應該參考一下18.7和18.8。其中有一些有關建庫的重要信息和有用的技巧。
請參見:
18.7當一個庫被連接到目標上時,庫中的所有函數(shù)是否都會被加到一個“.EXE"文件中?
18.8可以把多個庫函數(shù)包含在同一個源文件中嗎?
建立一個數(shù)據(jù)庫是為了把可重復使用的函數(shù)放在一起,供其它程序員和程序共享。例如,你的幾個程序可能都會用到一些通用的功能函數(shù),你不必在每個程序中都復制這些源代碼,而只需把這些函數(shù)集中到一個函數(shù)庫中,然后用連接程序把它們連接到你的程序中去。這種方法有利于程序的維護,因為你可以在一個集中的地方而不是幾個分散的地方維護你的函數(shù)。
如果你在小組環(huán)境中工作,那么你應該把你的可重復使用的函數(shù)放到一個庫中,這樣其它小組成員就可以把你的函數(shù)連接到他們的程序中去,從而節(jié)省了他們復制或從頭開始寫這些函數(shù)的時間。此外,在一個包含幾個模塊的大項目中,可以把那些自始至終都要用到的“框架”支持函數(shù)包含到一個庫中。
編譯程序中包含一個庫管理器(通常叫做LIB.EXE或其它類似的名字),可用來在函數(shù)庫中增減目標代碼模塊(.obj)。有些編譯程序允許你在它們的集成開發(fā)環(huán)境中維護你的庫,而不必人為地啟動庫管理器。無論如何,你都應該參考一下18.7和18.8。其中有一些有關建庫的重要信息和有用的技巧。
請參見:
18.7當一個庫被連接到目標上時,庫中的所有函數(shù)是否都會被加到一個“.EXE"文件中?
18.8可以把多個庫函數(shù)包含在同一個源文件中嗎?18.10.
如果一個程序包含多個源文件,怎樣使它們都能正常工作?
編譯程序中包含一個MAKE工具(通常叫做MAKE.EXE,NMAKE.EXE或其它類似的名字),其作用是記錄項目以及組成項目的源文件之間的依賴關系。下面是一個典型的MAKE文件的例子。myapp.ohj:
myapp.c
myapp.h
cl-cmyapp.cutility.obj:
utility.c
myapp.h
cl-cutility.cmyapp,exe:
myapp.obj
utility.obj
clmyapp.obj
utility.obj
這個例子表明myapp.obj依賴于myapp.c和myapp.h,utility.obj依賴于utility.c和myapp.h,myapp.exe依賴于myapp.obj和utility.obj。在表示依賴關系的每一行下面,都附有一條對相應的目標進行重新編譯或重新連接的編譯程序命令。例如,myapp.obj是通過執(zhí)行下面的命令行重新生成的:
cl-cmyapp.c
在上面的例子中,只有在myapp.c或myapp.h的時間標志晚于myapp.obj的時間標志時,myapp.obj才會被重新編譯。同樣,只有在utility.c或myapp.h的時間標志晚于utility.obj的時間標志時,utility.obj才會被重新編譯;只有在myapp.obj或utility.obj的時間標志晚于myapp.exe的時間標志時,myapp.exe才會被重新連接。
如果一個大型項目包含著源文件依賴關系,那么用MAKE文件來處理是非常方便的。MAKE工具及其相關的命令和實現(xiàn)因編譯程序的不同而不同——關于如何使用MAKE工具,你可以查閱你的編譯程序文檔。
今天,大多數(shù)編譯程序都帶有集成開發(fā)環(huán)境,你可以在其中用項目文件來管理程序中的多個源文件,如果你有一個集成環(huán)境,你就不必去了解MAKE工具的復雜用法,并且可以很方便地管理項目中的源文件,因為集成環(huán)境會為你記錄所有的源文件依賴關系。
請參見:
18.1程序是應該寫成一個源文件還是多個源文件?18.11.
連接過程中出現(xiàn)"DGROUP:groupexceeds64K"消息是怎么回事?
如果在連接時看到這條出錯消息,那是連接程序在指示數(shù)據(jù)(DGROUP)段中的近程數(shù)據(jù)(靜態(tài)數(shù)組元素,全局變量等)超過了64KB。解決這個問題的辦法有以下幾種:
?減少一些全局變量;
?減少程序的棧;
?用動態(tài)存儲分配技術為數(shù)據(jù)元素分配動態(tài)內(nèi)態(tài),而不把它們定義為靜態(tài)型或全局型;
?把數(shù)據(jù)元素說明為遠程型而不是近程型。
減少一些全局變量可能要求對程序的內(nèi)部結構進行重新設計,但這是值得的。從本質(zhì)上講,全局變量的維護很可能是一場惡夢,因此只有在確實需要時才能使用全局變量。如果你分配了大量的空間作為棧空間,那么你應該試試減少??臻g,看看是否能增加可用的內(nèi)存。如果你在程序中使用了大量靜態(tài)數(shù)據(jù),那么你應該想辦法重新安排這些靜態(tài)數(shù)據(jù),并且為它們分配動態(tài)的而不是靜態(tài)的內(nèi)存。這種技術可以釋放近程堆,并且使你能從遠程堆中分配內(nèi)存(見18.15中有關近程堆和遠程堆的討論)。
請參見:
18.12怎樣防止程序用盡內(nèi)存?
18.13如果程序大太而不能在DOS下運行,怎樣才能使它在DOS下運行呢?
18.14怎樣才能使DOS程序獲得超過640KB的可用內(nèi)存呢?
18.15近程型(near)和遠程型(far)的區(qū)別是什么?18.12.
怎術防止程序用盡內(nèi)存?
如果你使用了大量的靜態(tài)數(shù)據(jù),那么你應該考慮使用動態(tài)內(nèi)存分配技術。通過使用動態(tài)內(nèi)存分配技術(即使用malloc()和calloc()函數(shù)),你可以在需要時動態(tài)地分配內(nèi)存,在不需要時釋放內(nèi)存。這種方法有幾個好處:首先,動態(tài)內(nèi)存分配技術會使程序的效率更高,因為程序只在需要時才使用內(nèi)存,并且只使用所需大小的內(nèi)存空間。這樣,靜態(tài)和全局變量就不會占用大量的空間。其次,你可以通過檢查malloc()和calloc()函數(shù)的返回值來掌握內(nèi)存不足的情況。
如果你的程序特別大,你可能要使用覆蓋管理程序或DOS擴展程序,或者使用其它內(nèi)存分配機制,例如EMS和XMS(有關內(nèi)容見18.13和18.14)。
請參見:
18.11連接過程中出現(xiàn)"DGROUP:groupexceeds64K"消息是怎么回事?
18.13如果程序太大而不能在DOS下運行,怎樣才能使它在DOS下運行呢?
18.14怎樣才能使DOS程序獲得超過640KB的可用內(nèi)存呢?
18.15近程型(near)和遠程型(far)的區(qū)別是什么?18.13.
如果程序太大而不能在DOS下運行,怎樣才能使它在DOS下運行呢?
如果你的程序因太大(超過640KB)而無法在DOS下運行,有兩種辦法可為該程序提供更多的內(nèi)存。一種辦法是使用覆蓋管理程序(overlaymanager)。覆蓋管理程序用來管理程序的模塊,并根據(jù)需要把它們從磁盤中讀入內(nèi)存或從內(nèi)存中刪去。這樣,即使你的程序有幾兆字節(jié)那么大,仍然可以在只有640KB可用內(nèi)存的計算機上運行。一些高級的覆蓋管理程序允許你對需要同時讀入和刪除的模塊進行“編組”,這有助于你通過精心調(diào)整程序來改善它的性能。其它一些稍差的覆蓋管理程序不具備這種功能,因此使用它們時你無法通過編組方式去精心調(diào)整覆蓋模塊。
另一種獲得更多的可用內(nèi)存的辦法是使用DOS擴展程序(DOSextender),DOS擴展程序是一種特殊的應用程序,它通過使用386,486或更新機型的保護模式,按一個平面地址空間的方式來存取多達數(shù)兆字節(jié)的內(nèi)存。當你的程序和DOS擴展程序連接時,DOS擴展程序的代碼將成為該程序的啟動代碼的一部分。當你的程序被執(zhí)行時,DOS擴展程序?qū)⒈谎b入,并且將掌握程序的控制權。所有的內(nèi)存分配調(diào)用都要通過DOS擴展程序來進行,這樣就跳過了DOS,而由DOS擴展程序來分配超過640KB的內(nèi)存。
遺憾的是,DOS擴展程序也有一些明顯的缺點,其中之一就是,在你發(fā)行你的程序時,大多數(shù)DOS擴展程序要求你交納運行版稅。這可能非常昂貴,特別是在你有很多用戶時。也有少數(shù)編譯程序帶有免收版稅的DOS擴展程序,但這只不過是一種例外。使用DOS擴展程序的另一個缺點是它通常要求你通過修改源代碼而不是通過DOS調(diào)用來使用其應用編程接口(API)。
覆蓋管理程序一般不要求運行費用,因此它具有較高的性能價格比,并且比DOS擴展程序更便宜。此外,在使用覆蓋管理程序時,一般不需要修改源代碼,在大多數(shù)情況下,使用覆蓋管理程序?qū)Τ绦騺碚f是透明的。
請參見:
18.11連接過程中出現(xiàn)"DGROUP:groupexceeds64K"消息是怎么回事?
18.12怎樣防止程序用盡內(nèi)存?
18.14怎樣才能使DOS程序獲得超過640KB的可用內(nèi)存呢?
18.15近程型(near)和遠程型(far)的區(qū)別是什么?18.14.
怎樣才能使DOS程序獲得超過640KB的可用內(nèi)存呢?
當你發(fā)現(xiàn)自己遇到內(nèi)存危機的情況,需要在DOS程序中使用超過640KB的內(nèi)存時,你可以用幾種辦法來獲得更多的可用內(nèi)存。一種辦法是使用磁盤交換技術(diskswappin’g),即把內(nèi)存中不需要的數(shù)據(jù)元素(變量、數(shù)組、結構等)寫到磁盤上,并把它們原來占用的內(nèi)存空間釋放掉(使用free()函數(shù)),從而使程序獲得更多的可用內(nèi)存。當需要使用被交換到磁盤上的數(shù)據(jù)時,你可以把其它不需要的數(shù)據(jù)交換到磁盤上,然后把要用的數(shù)據(jù)從磁盤上讀到內(nèi)存中。遺憾的是,這種辦法要求編寫大量的代碼,而且實現(xiàn)起來比較麻煩。
另一種獲得超過640KB可用內(nèi)存的辦法是使用其它內(nèi)存資源一EMS(擴充內(nèi)存)或XMS(擴展內(nèi)存)。EMS和XMS指的是分配640KB區(qū)域以上的內(nèi)存的兩種方法,下文將分別對其進行介紹。
EMS指的是擴充內(nèi)存規(guī)范(ExpandMemorySpecification),它是由Lotus,Intel和Microsoft共同制定的,用來在IBM兼容機上訪問1MB以上的內(nèi)存區(qū)域。目前該規(guī)范有兩種版本在被使用:LIM3.2和LIM4.O。LIM4.O是新的版本,它克服了LIM3.2的一些局限性。在裝入擴充內(nèi)存管理程序(例如DOS中的EMM386.EXE)后,你就可以使用擴充內(nèi)存了。你的程序可以向擴充內(nèi)存管理程序發(fā)出要求使用擴充內(nèi)存的請求,擴充內(nèi)存管理程序?qū)⑹褂靡环N叫做成組交換(bankswitching)的技術,把位于IMB以上區(qū)域中的內(nèi)存暫時移到640KB和1MB之間的上位內(nèi)存中的一個空閑區(qū)中。成組交換技術包括這樣一些內(nèi)容:接受應用程序的內(nèi)存分配請求,并通過每次分配16KB上位內(nèi)存的方式來映射并管理1MB以上區(qū)域中的內(nèi)存。
擴展內(nèi)存在裝入擴展內(nèi)存管理程序(例如DOS中的HIMEM.SYS)后才會起作用。你的程序可以向擴展內(nèi)存管理程序發(fā)出要求使用擴展內(nèi)存塊(EMB)的請求。在申請擴展內(nèi)存時,不需要使用“成組交換技術”,你的程序只需向擴展內(nèi)存管理程序發(fā)一個函數(shù)調(diào)用來申請一塊位于1MB以上區(qū)域中的內(nèi)存。不幸的是,在DOS下位于1MB以上存儲區(qū)內(nèi)的代碼無法被執(zhí)行,因此你無法執(zhí)行在擴展內(nèi)存中的代碼。同樣,你也不能直接尋址存在擴展內(nèi)存中的數(shù)據(jù),所以,許多程序員喜歡在常規(guī)內(nèi)存(640KB以下)中建立一個“緩沖區(qū)”,從而為常規(guī)內(nèi)存和擴展內(nèi)存提供一個交換空間。
擴充內(nèi)存所使用的技術比較舊,并且有些過時了。當基于DOS的帶有擴充內(nèi)存的計算機剛出現(xiàn)時,擴充內(nèi)存的使用極為普遍。使用擴充內(nèi)存技術比使用擴展內(nèi)存技術要慢一些。實際上,通過在config.sys文件的EMM386.EXE設置項中加入NOEMS標志,今天的許多PC機配置都已完全取消了擴充內(nèi)存。大多數(shù)現(xiàn)代程序已經(jīng)放棄了舊的擴充內(nèi)存技術,而使用了新的擴展內(nèi)存技術。
如果你的程序要在高于1MB的區(qū)域內(nèi)尋址,你應該使用擴展內(nèi)存而不是擴充內(nèi)存。與使用擴充內(nèi)存時相比,在使用擴展內(nèi)存時,你的程序?qū)@得更高的穩(wěn)定性和執(zhí)行速度。
實現(xiàn)擴展內(nèi)存和擴充內(nèi)存的具體步驟已超出了本書的范圍。如果要解釋如何用這些技術來訪問內(nèi)存,恐怕就要再寫一章了。EMS(擴充內(nèi)存規(guī)范)和XMS(擴展內(nèi)存規(guī)范)文檔可以直接從Mcrosoft公司獲得,也可以從CompuServe這樣的網(wǎng)絡服務器上卸載下來,這些文檔詳細地介紹了EMS和XMS的應用編程接口(API)以及每一項技術的具體用法。
請參見:
18.11連接過程出現(xiàn)"DGROUP:groupexceeds64K"消息是怎么回事?
18.12怎樣防止程序用盡內(nèi)存?
18.13如果程序太大而不能在DOS下運行,怎樣才能使它在DOS下運行呢?
18.15近程型(near)和遠程型(far)的區(qū)別是什么?18.15.
近程型(near)和遠程型(far)的區(qū)別是什么?
DOS用一種分段結構來尋址計算機的內(nèi)存,每一個物理存儲位置都有一個可以用段一偏移量方式來訪問的相關地址。例如,下面就是一個典型的段式地址:
A000:1234
冒號左邊的部分代表段地址(A000),冒號右邊的部分代表相對于段地址的偏移量。DOS下的每個程序都是按這種方式訪問內(nèi)存的——盡管段一偏移量尋址方法的機理對大多數(shù)C程序員來說是隱蔽的。
當你的程序被執(zhí)行時,一個存放在數(shù)據(jù)段(DS)寄存器中的數(shù)據(jù)段地址將被賦給你的程序。這個缺省的數(shù)據(jù)段地址指向一個64KB的內(nèi)存空間,這個空間通常就被叫做近程型數(shù)據(jù)段。在這個近程型數(shù)據(jù)段空間中,你會找到程序的棧、靜態(tài)數(shù)據(jù)和近程堆。近程堆用來為程序啟動時所需的全局變量和其它數(shù)據(jù)元素分配內(nèi)存,在這個空間中分配的任何數(shù)據(jù)都被叫做近程型數(shù)據(jù)。例如,下面的程序在程序啟動時從近程堆中分配了32KB的近程型數(shù)據(jù):/*Note:ProgramusestheMediummemorymodel...*/#include<stdio.h>#include<alloc.h>#include<string.h>#include<stdlib.h>#include<dos.h>voidmain(void);voidmain(void){
char*near_data;
near_data=(char*)malloc((32*1024)*sizeof(char));
if(neardata==(char*)NULL)
{
printf("Whoopsie!Mallocfailed!\n");
exit(l);
}
strcpy(near_data,
"Thisstringisgoingtobe.storedinthenearheap");
printf("Addressofnear_data:%P\n",,&near_data);
free(near_data);}
在上例中,near_data是一個字符指針,程序分配給它一個32KB的內(nèi)存塊。在缺省情況下,這個32KB的內(nèi)存塊是從近程堆中分配的,并且
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 土地租賃協(xié)議2023
- 部編版六年級語文上冊第八單元知識梳理填空
- (2024)1-4酸鈉鹽生產(chǎn)建設項目可行性研究報告(一)
- 2023年天津市益中學校高考語文模擬試卷
- 2023年家政服務項目融資計劃書
- 零食行業(yè)藍皮書
- 電力電纜模擬習題+參考答案
- 養(yǎng)老院老人生活設施維修人員管理制度
- 養(yǎng)老院老人訪客管理制度
- 2024年旅游產(chǎn)品銷售與推廣合同3篇
- 財政投資評審咨詢服務預算和結算評審項目投標方案(技術標)
- 理工英語3-01-國開機考參考資料
- 綿綿用力久久為功-堅持每天進步一點點初中期末動員班會-2023-2024學年初中主題班會課件
- 2024屆湖北高三元月調(diào)考數(shù)學試卷含答案
- 視頻會議系統(tǒng)保障方案
- 西方園林史智慧樹知到期末考試答案章節(jié)答案2024年內(nèi)蒙古農(nóng)業(yè)大學
- 學年上學期期末職業(yè)高中高二年級數(shù)學練習試卷2
- 湖北省麻城市白鴨山礦區(qū)Ⅴ號礦段Ⅴ-1、Ⅶ號礦段Ⅶ-1、Ⅶ-5礦體飾面用花崗巖礦礦產(chǎn)資源開發(fā)利用與生態(tài)復綠方案
- 轉基因的科學-基因工程智慧樹知到期末考試答案章節(jié)答案2024年湖南師范大學
- 小學英語時態(tài)練習大全附答案
- 工程部設計部崗位職責
評論
0/150
提交評論