




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、轉(zhuǎn)載 如何減小EXE和DLL的文件長(zhǎng)度原文地址:如何減小EXE和DLL的文件長(zhǎng)度-作者:Knight原始鏈接也許很老了,但是確實(shí)很使用,所以扔過(guò)來(lái)了作者:Matt Pietrek翻譯:lostall原文:Under The Hood:Reduce EXE and DLL Size with LIBCTINY.LIB,January 2001聲明:嚴(yán)格地講,這不是一篇翻譯,我更愿意把它叫作意譯。即,我盡力保證文章內(nèi)容與原文完全一致,但我不保證與原文表達(dá)完全一致。特別地,對(duì)常用術(shù)語(yǔ)、我拿不準(zhǔn)的句子,或者我懶得寫漢字的話,我會(huì)直接引用英文。如果可能,讀者還是盡量閱讀原文為最佳。摘要這篇文章講述了如何
2、減小EXE和DLL的文件長(zhǎng)度。第一個(gè)小技巧是使用/OPT:NOWIN98鏈接選項(xiàng),可以讓Section按512字節(jié)對(duì)齊,而不是默認(rèn)的4K字節(jié)。這只是小case,這篇文章最動(dòng)人之處在于它模擬實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的Run time Library:libctiny.lib。麻雀雖小五臟俱全。(1)VC的運(yùn)行時(shí)庫(kù)會(huì)創(chuàng)建一個(gè)自己的heap,而libctiny.lib里的malloc等函數(shù)只是簡(jiǎn)單地調(diào)用GetProcessHeap()。(2)libctiny.lib實(shí)現(xiàn)了簡(jiǎn)單的Startup函數(shù),關(guān)鍵之處在于開(kāi)始運(yùn)行時(shí)要調(diào)用靜態(tài)C+成員變量的構(gòu)造函數(shù),結(jié)束時(shí)調(diào)用靜態(tài)C+成員變量的析構(gòu)函數(shù)。(3)本文最精彩的地
3、方是介紹了VC里是怎么處理靜態(tài)C+成員的構(gòu)造和析構(gòu)的,不過(guò)文中對(duì)于如何執(zhí)行析構(gòu)函數(shù)并沒(méi)有講全,沒(méi)有說(shuō)明atexit是何時(shí)調(diào)用的。我補(bǔ)充以下測(cè)試數(shù)據(jù):$E4:00401117 push ebp 00401118 mov ebp,esp 0040111 Acall$E1(0040112 d)/function for executing constructor 0040111 Fcall$E3(00401143)/function for executingatexit00401124 cmp ebp,esp 00401126 call _chkesp(00401727)0040112 Bpop
4、ebp 0040112 Cret$E1:0040112 Dpush ebp 0040112 Emov ebp,esp 00401130 mov ecx,offset g_TestClassInstance(00405758)/this指針00401135 callILT+10(TestClass:TestClass)(0040100 f)0040113 Acmp ebp,esp 0040113 Ccall _chkesp(00401727)00401141 pop ebp 00401142 ret$E3:00401143 push ebp 00401144 mov ebp,esp 004011
5、46 push offset$E2(0040115 c)/function for executing destructor 0040114 Bcall atexit(00401379)/function for adding the function pointer of$E2into the list of static destructors 00401150 add esp,4 00401153 cmp ebp,esp 00401155 call _chkesp(00401727)0040115 Apop ebp 0040115 Bret$E2:0040115 Cpush ebp 00
6、40115 Dmov ebp,esp 0040115 Fmov ecx,offset g_TestClassInstance(00405758)00401164 callILT+0(TestClass:TestClass)(00401005)004011 69 cmp ebp,esp 0040116 Bcall _chkesp(00401727)00401170 pop ebp 00401171 ret在執(zhí)行_initterm時(shí)會(huì)調(diào)用$E4,而$E4會(huì)首先調(diào)用$E1執(zhí)行構(gòu)造函數(shù),然后緊接著調(diào)用$E3把析構(gòu)函數(shù)的地址$E2加入到list of static destructors中。我早在MSJ
7、 1996年10月份的專欄里,就提出了一個(gè)關(guān)于可執(zhí)行文件大小的問(wèn)題。那個(gè)時(shí)侯一個(gè)簡(jiǎn)單的Hello World的程序編譯后有32KB那么大。對(duì)于此后的兩個(gè)編譯器版本,問(wèn)題也只是稍微好了一點(diǎn)而已?,F(xiàn)在用VC6.0編譯同樣的程序也達(dá)到了28K。在那個(gè)專欄里,我提供了一個(gè)運(yùn)行時(shí)庫(kù)的替代品,可以讓你創(chuàng)建非常小的可執(zhí)行程序。雖然在適用性上有一些限制,但在我自己的很多程序里都用得非常好。經(jīng)歷了這么長(zhǎng)時(shí)間,我決定是時(shí)侯對(duì)這些限制做一些修正了。同時(shí)這也是一個(gè)非常好的機(jī)會(huì)可以給大家描述一個(gè)很少有人知道的鏈接器選項(xiàng),它可以更進(jìn)一步的減小程序的大小。EXE and DLL Size在開(kāi)始進(jìn)入運(yùn)行時(shí)庫(kù)替代品的代碼之前,
8、有必要花點(diǎn)時(shí)間復(fù)習(xí)一下為什么簡(jiǎn)單的EXEs和DLLs會(huì)比你想象中的大??紤]下面這個(gè)典型的Hello World程序:#include void main()printf(Hello World!n);讓我們以大小優(yōu)先的方式編譯程序(譯注:即編譯器選項(xiàng)/O1,最小化大小),并生成一個(gè)map文件。在VC的命令行下,使用如下的語(yǔ)法:Cl/O1 Hello.CPP/link/MAP首先看一看.MAP文件,F(xiàn)igure 1中是一個(gè)減化的版本。注意觀察main函數(shù)的地址(0001:00000000)和printf函數(shù)的地址(0001:0000000 C),你可以推斷main函數(shù)的大小只有0xC個(gè)字節(jié)。再看
9、看文件的最后一行,_chkstk函數(shù)的地址是0001:00003B10,你可以推斷出執(zhí)行程序中的代碼至少有0x3B10個(gè)字節(jié)。即往屏幕上寫個(gè)Hello World需要超出14KB的代碼?,F(xiàn)在瀏覽一遍.MAP文件中的其它部分。有些函數(shù)還是有意義的,比如_initstdio函數(shù)。畢竟printf是把輸出寫到一個(gè)文件中,所以一些底層的為stdio提供支持的運(yùn)行時(shí)庫(kù)函數(shù)還是有必要的。同樣的,也可以估計(jì)到printf的代碼可能會(huì)調(diào)用strlen,所以包含strlen也不會(huì)讓人感到奇怪。然而,看一看其他的一些函數(shù),比如_sbh_heap_init。這是用于初始化運(yùn)行時(shí)庫(kù)的small block heap的
10、函數(shù)。Win32系統(tǒng)通過(guò)HeapAlloc家族的函數(shù)提供它們自己的堆。因?yàn)槭褂米约旱亩丫哂袧撛诘男阅苌系暮锰?,所以盡管VC庫(kù)可以選擇使用Win32的堆函數(shù),但是它沒(méi)這么做。結(jié)果就是,你的執(zhí)行程序里包含了比需要的更多的代碼。盡管有些人可能不關(guān)心運(yùn)行時(shí)庫(kù)實(shí)現(xiàn)了自己的heap,但另外有些情況你不能漠然視之。考慮map文件中靠近最下面的_crtMessageBoxA函數(shù)。這個(gè)函數(shù)允許運(yùn)行時(shí)庫(kù)調(diào)用MessageBox函數(shù),而不用強(qiáng)迫執(zhí)行程序鏈接到USER32.DLL。對(duì)于一個(gè)簡(jiǎn)單的Hello World程序,你很難預(yù)料到它還要調(diào)用MessageBox。再看看另一個(gè)例子:_crtLCMapStringA函
11、數(shù),它實(shí)現(xiàn)字符串的locale-dependent transformations。盡管Microsof是有一些責(zé)任提供本地化支持,但很多程序并不真的需要它。為什么要讓不使用locales的程序付出使用locales的代價(jià)呢?盡管我還可以繼續(xù)列舉一些包含了不需要的代碼的例子,但現(xiàn)在這些已經(jīng)足夠證明我的論點(diǎn)。一些典型的小程序里包含了大量沒(méi)被用到的代碼。對(duì)于他們各自而言,產(chǎn)生的影響并不大,但是把所有情況累加起來(lái),你就會(huì)發(fā)現(xiàn),代碼變得太大了!What About the C+Runtime Library DLL?思維敏捷的讀者可能會(huì)問(wèn),Hey Matt!為什么你不用運(yùn)行時(shí)庫(kù)的DLL版本?要是在過(guò)去
12、,我會(huì)辯解說(shuō)沒(méi)有在Windows 95,98,NT 3.51,NT 4.0等操作系統(tǒng)上命名一致的C+運(yùn)行時(shí)庫(kù)的DLL版本。幸運(yùn)的是,現(xiàn)在已經(jīng)今非昔比,在大多數(shù)情況下你可以依賴MSVCRT.DLL,它在你機(jī)器上總是存在的。打開(kāi)這個(gè)開(kāi)關(guān)(譯注:即選擇運(yùn)行時(shí)庫(kù)的DLL版本,比如/MD)然后重新編譯Hello.cpp,生成的可執(zhí)行程序只有16KB了。結(jié)果并不壞,但你還可以做得更好。更重要的是,你只不過(guò)是把所有不需要的代碼移到了別的地方而已(即:MSVCRT.DLL)。另外,當(dāng)你的程序啟動(dòng)時(shí),另一個(gè)DLL必須被裝載并且初始化,這個(gè)初始化包括你可能并不關(guān)心的本地化支持等等。如果MSVCRT.DLL滿足你的
13、需要,當(dāng)然可以繼續(xù)用它。但是,我相信一個(gè)精簡(jiǎn)的靜態(tài)鏈接地運(yùn)行時(shí)庫(kù)仍然有它的存在價(jià)值。我可能是在和風(fēng)車作戰(zhàn)(譯注:取自唐吉訶的風(fēng)車大戰(zhàn),應(yīng)該解釋為理想主義),但我和讀者之間的e-mail交流顯示我并不孤單,總是有人想要最小的代碼。在現(xiàn)在這個(gè)遍布可寫CD,DVD,高速Internet連接的年代里,人們很少擔(dān)心代碼的大小。但是在我家里最快的Internet連接也只有24Kbps,我憎恨在瀏覽網(wǎng)頁(yè)時(shí)要浪費(fèi)時(shí)間下載臃腫的控件。作為原則,我希望我的代碼盡可能的小巧。我不想load任何我沒(méi)有真正用到的DLLs。就算我可能需要一個(gè)DLL,我也要盡可能地delayload它,這樣我才不會(huì)為裝載它而付出代價(jià),直到
14、我真正用到了它。Delayloading是我在以前的專欄里討論過(guò)的一個(gè)主題,我強(qiáng)烈推薦你去熟悉它。初學(xué)者可以從Under the Hood in the December 1998 issue of MSJ開(kāi)始。(譯注:這篇文章的譯文在此)Digging Deeper既然已經(jīng)解決了程序中未使用代碼的問(wèn)題,我們?cè)俎D(zhuǎn)向可執(zhí)行文件本身。如果你對(duì)我的Hello.exe運(yùn)行DUMPBIN/HEADERS的話,會(huì)發(fā)現(xiàn)輸出以下兩行:(譯注:section alignment是內(nèi)存中節(jié)對(duì)齊的大小,是文件中節(jié)對(duì)齊的大小,詳細(xì)內(nèi)容參見(jiàn)IMAGE_OPTIONAL_HEADER)1000 section align
15、ment 1000 第二行很有趣,它是說(shuō)在執(zhí)行文件中每一個(gè)code和data段都是按4KB(0x1000)字節(jié)對(duì)齊的。因?yàn)閟ections在文件中是連續(xù)存儲(chǔ)的,不難發(fā)覺(jué)在上一個(gè)section的結(jié)尾和下一個(gè)section的起始之間浪費(fèi)的空間最多可達(dá)到4KB。如果我用一個(gè)比VC6.0更早的linker鏈接這個(gè)程序的話,會(huì)發(fā)現(xiàn)有一些不同,如下所示:1000 section alignment 200 關(guān)鍵的差異是section是按512(0x200)字節(jié)對(duì)齊的,這減少了浪費(fèi)的空間。VC6.0里,鏈接器缺省的是讓section在文件中的對(duì)齊方式等于在內(nèi)存中的對(duì)齊方式。這種做法在Windows 9x上對(duì)
16、啟動(dòng)速度有輕微的提高,但是使執(zhí)行程序變大了。幸運(yùn)的是,VC linker有一種方法可以回到以前的做法,這個(gè)開(kāi)關(guān)就是/OPT:NOWIN98。Rebuild Hello.cpp,增加的這個(gè)開(kāi)關(guān)可以使執(zhí)行文件的大小減少到21KB,節(jié)省了7KB。如果鏈接到MSVCRT.DLL并且同時(shí)使用/OPT:NOWIN98,執(zhí)行文件的大小一下子降到了2560個(gè)字節(jié)!LIBCTINY:A Minimal Runtime Library既然你已經(jīng)理解了為什么簡(jiǎn)單的EXEs和DLLs會(huì)那么大,那么是時(shí)侯介紹我的新的改進(jìn)了的運(yùn)行時(shí)庫(kù)的替代品了。在October 1996的專欄里(前面提過(guò)),我創(chuàng)建了一個(gè)小的靜態(tài).LIB
17、文件,用來(lái)替換或者補(bǔ)充Microsoft的LIBC.LIB和LIBCMT.LIB。我把它叫做LIBCTINY.LIB,因?yàn)樗荕icrosoft自己的運(yùn)行時(shí)庫(kù)源程序的一個(gè)非常stripped-down的版本。LIBCTINY.LIB是給那些簡(jiǎn)單的不需要很多運(yùn)行時(shí)庫(kù)支持的應(yīng)用程序使用的。因此,它不適用于MFC程序,或者其它需要大量使用C+運(yùn)行時(shí)庫(kù)的復(fù)雜情況。LIBCTINY.LIB的理想對(duì)象是調(diào)用了一些Win32 API函數(shù)并且可能會(huì)顯示一些簡(jiǎn)單輸出的小程序或DLLs。LIBCTINY.LIB背后有兩個(gè)指導(dǎo)原則。首先,它用非常簡(jiǎn)單的代碼替換了Visual C+的標(biāo)準(zhǔn)啟動(dòng)函數(shù)。這個(gè)簡(jiǎn)化的代碼不引用
18、任何更深?yuàn)W的運(yùn)行時(shí)庫(kù)函數(shù),比如_crtLCMapStringA。正因如此,極大地減少了鏈接到你的執(zhí)行文件中的無(wú)關(guān)代碼。正如我稍后將說(shuō)明的那樣,LIBCTINY的函數(shù)在調(diào)用你的WinMain,main或DllMain之前僅僅執(zhí)行了最少的任務(wù)。LIBCTINY.LIB的第二個(gè)指導(dǎo)原則是用已經(jīng)存在于Win32系統(tǒng)DLLs的代碼實(shí)現(xiàn)相當(dāng)規(guī)模的函數(shù),比如malloc,free,new,delete,printf,strupr,strlwr等等??匆谎踦rintf.cpp(Figure 2)中printf的實(shí)現(xiàn),體會(huì)一下我說(shuō)的意思。在LIBCTINY.LIB的原始版本里有兩個(gè)限制一直困擾著我。第一,原始的
19、版本里不支持DLLs。你可以創(chuàng)建小的Console和GUI執(zhí)行程序,但不幸的是你不能創(chuàng)建一個(gè)小的DLL。第二,原始的版本里不支持靜態(tài)C+構(gòu)造和析構(gòu)。我這里指的是在全局范圍內(nèi)聲明的構(gòu)造和析構(gòu)。在新版本里我已經(jīng)加上了提供這種支持的基本代碼。在這個(gè)過(guò)程中,我也學(xué)到了很多關(guān)于編譯器和運(yùn)行時(shí)庫(kù)為實(shí)現(xiàn)靜態(tài)構(gòu)造和析構(gòu)玩的一個(gè)復(fù)雜游戲的知識(shí)。The Dark Underbelly of Constructors當(dāng)編譯器處理一個(gè)有靜態(tài)Constructor的源文件時(shí),它生成兩個(gè)東西。首先是一個(gè)名字類似于$E2的一小段代碼,負(fù)責(zé)調(diào)用Constructor。其次是一個(gè)指向這段代碼的指針。這個(gè)指針被寫到.OBJ文件中
20、一個(gè)叫做.CRT$XCU的特殊節(jié)中。為什么叫這么有趣的名字?原因有點(diǎn)復(fù)雜。讓我提供一點(diǎn)別的數(shù)據(jù)幫助解釋。如果你檢查VC運(yùn)行時(shí)庫(kù)源代碼(比如,CINITEXE.C),你會(huì)發(fā)現(xiàn)下面這段代碼:#pragma data_seg(.CRT$XCA)_PVFV _xc_a=NULL;#pragma data_seg(.CRT$XCZ)_PVFV _xc_z=NULL;上面的代碼創(chuàng)建了兩個(gè)數(shù)據(jù)段:.CRT$XCA和.CRT$XCZ。在每個(gè)段中放了一個(gè)變量(分別是_xc_a和_xc_z)。注意,段的名字非常類似于編譯器把Constructor代碼指針?lè)诺降?CRT$XCU段的名字。這里需要了解一點(diǎn)Linker
21、的理論。當(dāng)處理所有的段以產(chǎn)生最終的PE文件時(shí),鏈接器合并所有相同名字的段的數(shù)據(jù)。所以,如果A.OBJ有一個(gè)段叫.data,B.OBJ也有一個(gè)段叫.data,那么A.OBJ里.data段的數(shù)據(jù)和B.OBJ里.data段的數(shù)據(jù)會(huì)被順序?qū)懙絇E文件中一個(gè)單獨(dú)的.data段中。段名里使用的$符號(hào)有特別的作用。當(dāng)遇到段名里有$符號(hào)的時(shí)侯,鏈接器把$之前的名字做為最終的段名。這樣,.CRT$XCA,.CRT$XCU,和.CRT$XCZ段被合并在一起,成為最終的執(zhí)行文件中的.CRT段。那么段名里$之后的部分是干什么用的呢?當(dāng)合并這種類型的段時(shí),鏈接器根據(jù)$之后的字符串的字典順序進(jìn)行處理。所以,.CRT$XC
22、A段內(nèi)的數(shù)據(jù)先處理,緊跟著的是.CRT$XCU段內(nèi)的數(shù)據(jù),最后是.CRT$XCZ。這是理解的關(guān)鍵點(diǎn)。運(yùn)行時(shí)庫(kù)代碼不知道一個(gè)指定的EXE或DLL里有多少個(gè)靜態(tài)的構(gòu)造函數(shù)需要被調(diào)用。但是,它知道在.CRT$XCu段內(nèi)的指向constructor code塊的指針。當(dāng)鏈接器合并所有的.CRT$XCU段時(shí),它產(chǎn)生的實(shí)際效果是創(chuàng)建了一個(gè)函數(shù)指針數(shù)組。通過(guò)定義在.CRT$XCA和.CRT$XCZ段內(nèi)的_xc_a和_xc_z變量,運(yùn)行時(shí)庫(kù)能夠可靠地定位函數(shù)指針數(shù)組的起點(diǎn)和終點(diǎn)。正如你可能料到的,調(diào)用模塊內(nèi)所有的靜態(tài)構(gòu)造函數(shù),只是簡(jiǎn)單的遍歷函數(shù)指針數(shù)組,依次調(diào)用每個(gè)指針。做這件事的函數(shù)是_initterm(F
23、igure 3),它與Visual C+運(yùn)行時(shí)庫(kù)里的源代碼是一樣的??紤]完所有的事以后,LIBCTINY讓static constructors運(yùn)行起來(lái)相對(duì)就簡(jiǎn)單了。主要就是定義正確的數(shù)據(jù)段(特別是.CRT$XCA和.CRT$XCZ),然后從啟動(dòng)代碼的正確地方調(diào)用_initterm。但是處理靜態(tài)析構(gòu)就要有點(diǎn)技巧了。不同于編譯器和鏈接器合謀為靜態(tài)constructor創(chuàng)建的函數(shù)指針數(shù)組,靜態(tài)destructor列表是在運(yùn)行時(shí)創(chuàng)建的。為了建立這個(gè)列表,編譯器產(chǎn)生對(duì)atexit函數(shù)的調(diào)用,它是Visual C+運(yùn)行時(shí)庫(kù)里的一個(gè)函數(shù)。atexit接受一個(gè)函數(shù)指針,然后把這個(gè)指針添加到一個(gè)FILO(先進(jìn)
24、后出)列表(譯注:其實(shí)就是stack)中。當(dāng)EXE或DLL卸載時(shí),運(yùn)行時(shí)庫(kù)遍歷這個(gè)列表,并且調(diào)用每個(gè)函數(shù)指針。LIBCTINY對(duì)atexit的實(shí)現(xiàn)比VC運(yùn)行時(shí)庫(kù)里的實(shí)現(xiàn)簡(jiǎn)單了很多。有三個(gè)函數(shù)和幾個(gè)靜態(tài)變量用于實(shí)現(xiàn)它,也在initterm.cpp中。_atexit_init簡(jiǎn)單地分配一個(gè)容納32個(gè)函數(shù)指針的數(shù)組,并把數(shù)組指針存到pf_atexitlist靜態(tài)變量中。atexit函數(shù)檢查數(shù)組中是否還有空間,如果有,就把函數(shù)指針加到數(shù)組的末尾。這段代碼的一個(gè)更強(qiáng)健的做法是當(dāng)需要時(shí)reallocate數(shù)組。最后,_DoExit函數(shù)使用你的朋友,_initterm,去遍歷數(shù)組,調(diào)用每個(gè)函數(shù)指針。理想情況
25、下,_DoExit應(yīng)該模仿VC運(yùn)行時(shí)庫(kù)的實(shí)現(xiàn),以相反的方向遍歷數(shù)組。但是LIBCTINY的目的只是為了簡(jiǎn)單小巧,沒(méi)有必要追求完美的兼容性。(譯注:C+標(biāo)準(zhǔn)規(guī)定Destructor的順序應(yīng)該與Constructor的順序相反。LIBCTINY沒(méi)有遵循這個(gè)規(guī)定,但也沒(méi)有什么影響。應(yīng)用程序也應(yīng)該盡量避免使用構(gòu)造或析構(gòu)順序有依賴關(guān)系的全局變量。)LIBCTINYs Minimal Startup Routines現(xiàn)在讓我們看看LIBCTINY對(duì)小DLL的新支持。像EXE一樣,技巧在于使DLL的入口點(diǎn)代碼盡可能的小,并且去除可能引起大量其他代碼的無(wú)用程序。Figure 4展示了最小的DLL啟動(dòng)代碼。當(dāng)你
26、的DLL被裝載時(shí),是這段代碼,而不是你的DllMain首先被執(zhí)行。_DllMainCRTStartup函數(shù)是你的DLL里執(zhí)行的起始點(diǎn)。在LIBCTINY的實(shí)現(xiàn)中,它首先檢查是否DLL處在DLL_PROCESS_ATTACH調(diào)用中。如果是,就調(diào)用_atexit_init(前面講過(guò)),然后通過(guò)_initterm調(diào)用靜態(tài)Constructor。函數(shù)的核心是調(diào)用DllMain,它是你在Dll里自己提供的。這個(gè)DllMain的調(diào)用對(duì)四種通知類型都適用(process attach/detach,and thread attach/detach)。DllMainCRTStartup要做的最后一件事是檢查D
27、ll是否處在DLL_PROCESS_DETACH調(diào)用中。如果是,就調(diào)用_DoExit。與前面講的一樣,這會(huì)導(dǎo)致所有的靜態(tài)析構(gòu)函數(shù)被調(diào)用。如果你對(duì)Console和GUI類型的EXE的啟動(dòng)代碼感到好奇的話,一定要看看CRT0TCON.CPP和CRT0TWIN.CPP。另一個(gè)值得查看的是在DLLCRTO.CPP(看Figure 4)的靠近最上面的一行代碼:#pragma comment(linker,/OPT:NOWIN98)它把一個(gè)鏈接器命令放到DLLCRTO.OBJ文件中,其作用是通知鏈接器使用/OPT:NOWIN98開(kāi)關(guān)。好處是你不用再手工地把/OPT:NOWIN98添加到你的make文件或工
28、程文件中。我考慮到如果你使用LIBCTINY,你應(yīng)該也會(huì)想使用/OPT:NOWIN98。Using LIBCTINY.LIB使用LIBCTINY非常簡(jiǎn)單。你需要做的所有事就是把LIBCTINY.LIB加到鏈接器的.LIB列表中。如果你正在使用Visual Studios IDE,應(yīng)該在Projects|Settings|Link下面。哪種類型的執(zhí)行文件都可以(console EXE,GUI EXE,or DLL),因?yàn)長(zhǎng)IBCTINY.LIB為每種類型都提供了適當(dāng)?shù)娜肟邳c(diǎn)。看一看Figure 5中的TEST.CPP。這個(gè)程序簡(jiǎn)單地使用了幾個(gè)LIBCTINY.LIB實(shí)現(xiàn)的函數(shù),并且包含了一個(gè)靜態(tài)
29、constructor和destructor的調(diào)用。當(dāng)我用Visual C+以正常方式編譯它時(shí),CL/O1 TEST.CPP生成的執(zhí)行文件是32768字節(jié)。簡(jiǎn)單地在命令行上加上LIBCTINY.LIB:CL/O1 TEST.CPP LIBCTINY.LIB生成的執(zhí)行文件縮減到了3072字節(jié)。你可能很想知道哪些運(yùn)行時(shí)庫(kù)函數(shù)LIBCTINY沒(méi)有實(shí)現(xiàn)。例如,在TEST.CPP中,有一個(gè)對(duì)strrchr的調(diào)用。這里沒(méi)有問(wèn)題,因?yàn)閂isual C+提供的LIBC.LIB和LIBCMT.LIB包含了這個(gè)函數(shù)。LIBCTINY.LIB和LIBC.LIB都實(shí)現(xiàn)了各種各樣的函數(shù)。LIBCTINY提供的明顯比LIBC.LIB的少。重要的是要讓鏈接器在解析函數(shù)調(diào)用時(shí)首先找到LIBCTINY的函數(shù),這樣LIBCTINY的函數(shù)才會(huì)被使用。如果有些函數(shù)LIBCTINY沒(méi)有實(shí)現(xiàn),鏈接
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 定遠(yuǎn)一中初中數(shù)學(xué)試卷
- 第六七單元的數(shù)學(xué)試卷
- 各地五年級(jí)期末數(shù)學(xué)試卷
- 2025年江西鷹潭市面向應(yīng)屆畢業(yè)生大學(xué)生鄉(xiāng)村醫(yī)生專項(xiàng)招聘2人筆試歷年專業(yè)考點(diǎn)(難、易錯(cuò)點(diǎn))附帶答案詳解
- 2025年年嘉興市婦幼保健院公開(kāi)招聘高層次人才35人(第一批)筆試歷年專業(yè)考點(diǎn)(難、易錯(cuò)點(diǎn))附帶答案詳解
- 2025年01月甘肅隴南康縣婦幼保健院招聘檢驗(yàn)科編外專業(yè)技術(shù)人員筆試歷年專業(yè)考點(diǎn)(難、易錯(cuò)點(diǎn))附帶答案詳解
- 肝功能不全的檢測(cè)與治療
- 2025至2030超聲波處理器行業(yè)市場(chǎng)深度研究與戰(zhàn)略咨詢分析報(bào)告
- 2025至2030產(chǎn)權(quán)式酒店行業(yè)市場(chǎng)深度研究及發(fā)展前景投資可行性分析報(bào)告
- 高中溫州一模數(shù)學(xué)試卷
- 工業(yè)企業(yè)常見(jiàn)安全隱患整改對(duì)應(yīng)依據(jù)標(biāo)準(zhǔn)全
- 放大繩安全技術(shù)交底
- 湖南文理學(xué)院輔導(dǎo)員考試真題2022
- 中醫(yī)四大經(jīng)典知識(shí)競(jìng)賽真題模擬匯編(共702題)
- 蜱蟲(chóng)病的防治
- 數(shù)學(xué)建模部分概念期末復(fù)習(xí)
- 中石化定額章節(jié)官方解析交流148篇答疑
- 福佳大化安全技術(shù)規(guī)程
- 高考英語(yǔ)備考經(jīng)驗(yàn)交流
- 處方點(diǎn)評(píng)指南:靜脈輸液
- 臨床科研設(shè)計(jì)(詳細(xì)知識(shí)點(diǎn)總結(jié))
評(píng)論
0/150
提交評(píng)論