原始的C運行時庫從來沒有想過必須支持從多個模塊構建的程序。它包含全局變量,如errno
和stdout
以及具有隱式全局狀態的函數,如strtok()
和malloc()
。您可以將DLL與他們自己的CRT副本鏈接起來,但這對設計DLL接口的方式提出了相當苛刻的要求。你必須非常小心地對從不依賴於CRT狀態。獲得這個錯誤幾乎不可能診斷運行時錯誤行爲。
對此的解決方法是在您的過程中只有一個一個 CRT副本。這是/ MD完成的,你最終會依賴於存儲在DLL中的CRT版本。由所有模塊共享。像msvcr120.dll一樣,由VS2013使用。
編譯器需要知道這個,以便它可以正確使用該DLL版本。一個簡單的例子是errno
,它是一個帶有/ MT的全局變量,但是被宏編輯爲帶有/ MD的函數調用,因此只有DLL中的一個全局用於跟蹤最後一個已知值。如果在編譯器的.h文件中使用/ MD,則將定義_DLL
宏。
另外一個副作用是編譯器自動爲msvcrt.lib或libcmt.lib插入鏈接指令(相當於#pragma註釋)。旨在幫助您避免錯誤,並省略明確指定CRT庫鏈接指令的需求。如果出現錯誤,則很難診斷鏈接器錯誤消息。與您嘗試鏈接.obj或。時獲得的種類不同。lib文件與/ MT和/ MD不匹配。哪一個當然不能正常工作,你不能對兩者都有依賴性。
中的.libs都不是導入庫
你的名字,ole32.lib,advapi32.lib,USER32.LIB列出的那些,其實都是導入庫。它們是標準的操作系統DLL。在運行時,程序將加載相應的DLL,從調試器中可以很容易看到。對於VS,你會在輸出窗口中看到它。值得注意的是,這些DLL實際上使用了與您的程序不同的CRT,它們綁定到c:\ windows \ system32 \ msvcrt.dll。 winapi經過精心設計,永遠不會造成這個問題。
做鏈接使用靜態或動態鏈接默認
沒有默認值,它取決於你鏈接的.lib。區分靜態鏈接庫和導入庫。導入庫是在構建DLL時創建的。它是一個不包含代碼的小文件,只是DLL中導出函數的名稱,因此鏈接器知道將條目放入程序的導入表中。當程序啓動時,DLL依賴項被解析並且導入的函數被加載器綁定。