复杂的C运行时库
復雜的C運行時庫
Posted on?2012-09-27 23:06?justin_s?閱讀(294) 評論(0)?編輯?收藏?http://www.cnblogs.com/justin_s/archive/2012/09/27/2706409.html
因為各種原因常加一些第三方庫到工程中。使用這些庫,最好能夠自己編譯,否則應該真的應該好好檢查一下它對C運行時庫的依賴情況,否則真的容易出現莫名其名的訪存錯誤。
總結一下,要檢查以下幾個方面:
1. 要檢查一下依賴的C runtime lib是debug或release版,不要混用二者。
2. 檢查C runtime lib是單線程版、靜態多線程還是動態鏈版。
?
我們先看CRTLib (C運行庫):
msdn 上有這樣一段話:
警告?不要混合使用運行時庫的靜態版本和動態版本。在一個進程中有多個運行時庫副本會導致問題,因為副本中的靜態數據不與其他副本共享。鏈接器禁止在 .exe 文件內部既使用靜態版本又使用動態版本鏈接,但您仍可以使用運行時庫的兩個(或更多)副本。例如,當與用動態 (DLL) 版本的運行時庫鏈接的 .exe 文件一起使用時,用靜態(非 DLL)版本的運行時庫鏈接的動態鏈接庫可能導致問題。(還應該避免在一個進程中混合使用這些庫的調試版本和非調試版本)。
還有這樣一張表:
Reusable Library??????????????? Switch??? Library??? Macro(s) Defined
----------------------------------------------------------------
Single Threaded???????????????????? /ML?????? LIBC?????????????? (none)
Static MultiThread????????????????? /MT?????? LIBCMT???????? _MT
Dynamic Link (DLL)????????????? /MD?????? MSVCRT??????? _MT and _DLL
Debug Single Threaded?????????? /MLd????? LIBCD????????? _DEBUG
Debug Static MultiThread??????? /MTd????? LIBCMTD??? _DEBUG and _MT
Debug Dynamic Link (DLL)??? /MDd????? MSVCRTD??? _DEBUG, _MT, and _DLL
?
這張表列出了Windows下有六種類型CRTLib(C運行庫),它們是使用不同的switch生成的,這些switch通過宏起作用。
其中MT和MD都適用于多線程,其區別是:
1. MT為靜態鏈接CRT,這樣編譯出來exe是自包含的,所以會相對大一些,但運行時不用再load CRT庫。
2. MD為動態鏈接CRT,編譯出來exe會小一些,運行時需要load CRT,性能有一點點損失。
任何工程都應該使用同樣的CRT Library。即要么都是/ML,要么都是/MTD, 如此類推。 如果一個程序中混合使用不同類型的CRT,有時可以通過link,這樣會存在不同CRT的copy,并會導致內存,比如:
1. 在一個lib中new出來內存,在另一個lib中delete,會crash。
2. 不能在多個lib中共享file handle,理由同上。
3. 一個lib中設置locale(本地化有關),不能在另一個lib中起作用。
?
其實對于Standard C++ Library也有類似的問題,我們這里同樣列出一張表:
當鏈接程序時,一個C運行庫會根據switch與你的程序鏈接,這是默認行為;但是如果你包含了C++標準頭文件,比如<ios>那么Standard C++ Library會被鏈接進來。
?
msvcrt.dll 與 msvcr71.dll
還有一個比較常見的dll叫msvcr71.dll,將之與msvcrt.dll放在一起說。msvcrt.dll 是系統的一部分,它是為將來系統級組件預留的。我們的程序應該使用、發布的是msvcr71.dll,而且當發布時,最好把這個dll放在程序的目錄下而非替換系統目錄下的同名dll.
目前而言,這兩個dll還是比較混亂的,如果你手上有個比較老的庫依賴mscvrt.lib,那么其中依賴的dll可能是mscrt.dll,而如果你重新編譯這個庫的話會發現c運行庫的依賴變成了mscrt71.dll。而把mscrt.dll和mscrt71.dll混用也是很不好的,同樣可能出現我們上而引用的msdn那段話中講的問題。
?
所以現在我在選擇第三方庫時會比較注意盡量選擇開源的庫;如果需要加入其他人編譯的庫,也會用比如dependence walker這樣的工具先檢查一下對C運行時的依賴情況。
推而廣之一下,其實不僅C運行時庫了,如果兩個第三方庫共同依賴了另外一個庫,那么這個庫的版本也應該被檢查。
?
博客園上也還有不少文章與本文講述的內容相近,比如以下兩篇:
1.?http://www.cnblogs.com/diyunpeng/archive/2011/06/16/2083085.html
2.?http://www.cnblogs.com/Frodo/archive/2008/02/04/1064267.html
總結