C++:關於庫項目的生成和使用

一、庫項目的生成

  • 靜態庫:函數和數據被編譯進一個二進制文件(.LIB文件)。在使用的靜態庫編譯鏈接可執行文件時,鏈接器從庫中複製這些函數並編譯到exe文件當中。也就是說發佈exe文件時,是不需要發佈被使用的靜態庫的。
  • 靜態庫的項目配置:(1)項目-> 屬性->常規->“MFC的使用”選擇“在靜態庫中使用MFC”(2)進入項目-> 屬性->C/C++->代碼生成->*“運行庫”選擇“多線程調試MTd”*或者“多線程MT”,如果是Debug模式選擇前者,Release模式選擇後者。
  • 動態庫:動態庫項目生成兩個文件引入庫(.lib)和一個DLL(.dll)。注意這個lib文件時不同於上邊的LIB文件的。引入庫文件(.lib)包含改DLL導出的函數名和變量名,而.dll文件包含該庫實際的函數和數據。當使用動態庫編程生成exe文件時只需要lib文件即可,但是發佈並運行exe文件時需要加載相應的dll文件。
  • 動態庫的項目配置:(1)項目-> 屬性->常規->“MFC的使用”選擇“在共享DLL中使用MFC”(2)項目-> 屬性->C/C++->代碼生成->*“運行庫”選擇“多線程調試DLL(/MDd)”*或者“多線程DLL(/MD)”,如果是Debug模式選擇前者,Release模式選擇後者。
  • /MT 的意思就是使用微軟的多線程靜態鏈接庫;/MD 的意思就是使用微軟的多線程動態鏈接庫。不要混合使用運行時庫的靜態版本和動態版本。在一個進程中使用同一個庫的多個版本時會導致問題,經常提示已在.obj中定義,因爲庫副本中的靜態數據不與其他庫副本共享。鏈接器禁止在 .exe 文件內部既使用靜態版本又使用動態版本鏈接。

二、庫項目函數的導出和導入

如果我們的程序想要使用(導入/加載)某個DLL中的函數,那麼該函數必須在DLL中是已經導出的。

1、從DLL中導出函數

  • def文件:只需要在EXPORT後邊加上要導出的函數名就行(只需要函數名,不需要形參)。其實def文件的功能相當於extern “C” __declspec(dllexport)
  • 使用_declspec(dllexport)聲明導出函數(既可以顯示又可以隱時)
    dllexport是在這些類、函數以及數據的申明的時候使用。使用了(dllexport)關鍵字,相當於聲明瞭緊接在(dllexport)關鍵字後面的相關內容是可以爲其他程序使用的。
  • Dll文件中可以同時使用上述兩種方法,但是網上大家都推薦使用第二種,好像第一種有的時候函數名會自己變。

2、隱式鏈接方式加載DLL

首先需要配置需要的lib文件,之後再採用extern或_declspec(dllimport)聲明。配置lib文件有兩種,一種是在項目屬性中配置,另一種是在程序中加入下述代碼(比如說使用的是A.lib文件),這兩種方式效果是一樣的。

#include "A.h"
#pragma comment(lib,"A.lib")
  • 可以使用extern聲明庫函數,即在使用之前,用extern聲明一下dll導出的函數即可,如extern int add(int a,int b)。但是還是建議用下邊這種方式:
  • 使用_declspec(dllimport)聲明庫函數。
    dllimport關鍵字是在外部程序需要使用DLL內相關內容時使用的關鍵字。當一個外部程序要使用DLL內部代碼(類,函數,全局變量)時,只需要在 程序內部使用(dllimport)關鍵字聲明需要使用的代碼就可以了。
    _declspec(dllexport)_declspec(dllimport)是相互呼應,只有在DLL內部用dllexport作了聲明,才能 在外部函數中用dllimport導入相關代碼。實際上,在應用程序訪問DLL時,實際上就是應用程序中的導入函數與DLL文件中的導出函數進行鏈接。

3、關於__declspec(dllexport)和__declspec(dllimport)的使用

經常是在.h文件中聲明函數/類/數據的導出和導入,那麼問題來了,庫文件的.h文件既被庫項目加載(這個時候應該是dllexport)又被將來使用庫文件的項目加載(這個時候應該是dllimport),那麼該怎麼辦呢,應當這麼辦:
在庫項目的開頭定義宏DLLProvider,然後在需要的.h文件中加入這樣的代碼,以後當使用dllexport或dllimport的時候,都使用DLL_EXPORT_IMPORT就行了。

 #ifdef DLLProvider
 #define DLL_EXPORT_IMPORT __declspec(dllexport) //在庫項目中使用
 #else
 #define DLL_EXPORT_IMPORT __declspec(dllimport)//在使用dll的項目中使用
 #endif

三、其他關鍵的命令字

1、extern"C"

我們經常在程序(尤其是一些年代比較久,比如說早期的庫文件裏)裏見到這樣的代碼

#ifdef __cplusplus 
extern "C" { 
#endif
...
#ifdef __cplusplus
  }
#endif

這個宏#ifdef __cplusplus意思是說,如果該文件是Cpp文件,extern "C" {}生效。當Cpp文件中出現這些代碼,意味着花括號裏邊的代碼是以C語言的編譯規則生成彙編語言。
雖然C++是在C語言的基礎上發展起來的,但是有些C代碼和C++的編譯規則存在一定差異。爲了兼容這部分代碼,C++創始人制定了上述的解決方法,在C++文件(也就是cpp文件)允許C語言代碼直接存在,只需要在頭上聲明一下這部分代碼需要按C語言的方法進行編譯,也就是extern "C"的存在

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章