1. 程式人生 > >C++:關於庫專案的生成和使用

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"的存在