首先,這不是什么很難做的事擦剑,但是妖胀,我還是記錄一下,因為這種方式我很容易就忘記了;堇铡W铡!個人不太習(xí)慣記住這些不是很常用的東西纠屋,但是涂臣,又時常在用的東西!
我們要明白DLL文件其實也是一個二進制的文件售担,只不多這個文件并不是可執(zhí)行的文件赁遗。所以從本質(zhì)上,他和可執(zhí)行文件是沒有任何的區(qū)別的族铆。
這里說下他們的主要區(qū)別岩四,可執(zhí)行文件中我們定義了main函數(shù)的入口,但是DLL中我們并沒有骑素,我們只是提供了對外的函數(shù)接口炫乓,并且這些對外的函數(shù)我們都使用了特殊的標記(_declspec(dllimport)和_declspec(dllexport))用來表明這個函數(shù)是個對外函數(shù)。當然這個標記也可以標識類献丑,表明這個類是一個對外類末捣。
下面來說這個標記的作用,我們在定義一個DLL的時候往往需要使用標記_declspec(dllexport)標明這是一個導(dǎo)出函數(shù)或者是一個導(dǎo)出類或者是一個導(dǎo)出的全局變量创橄,當我們需要引用DLL的導(dǎo)出函數(shù)或者導(dǎo)出類或者導(dǎo)出的全局變量的時候箩做,我們需要在被引用出使用標記_declspec(dllimport)標明這是一個導(dǎo)入函數(shù)或者導(dǎo)入類或者導(dǎo)入的全局變量(編譯器本身可以自行推到函數(shù)是否是需要導(dǎo)入的,不過顯示的指明聽說是可以提高效率的)妥畏。
這里有些注意事項:
編譯DLL時為啥沒有生成lib文件
c語言怎么調(diào)用dll文件
根據(jù)上述的方法我們自行定義一個DLL邦邦,代碼如下:
// file_name: DLLHeader.h
#pragma once
#ifdef EXPORT_WIN32POJ
#define EXPORTS_DEMO _declspec(dllexport)
#else
#define EXPORTS_DEMO _declspec(dllimport)
#endif
int EXPORTS_DEMO add(int a, int b);
// file_name:DLLSource.cpp
#include "DLLHeader.h"
int add(int a, int b)
{
return a + b;
}
編譯DLL的工程的時候安吁,我們需要增加預(yù)編譯宏EXPORT_WIN32POJ,才能正常編譯DLL燃辖,生成相應(yīng)的lib和dll文件鬼店,此處我們編譯的lib和dll的文件名分別為:Win32Project1.lib, Win32Project1.dll黔龟,為了引用該 dll 我們同時需要在可執(zhí)行程序代碼中引用 DLLHeader.h
可執(zhí)行程序代碼如下:
// file_name:Header.h
#pragma once
#include <iostream>
#include "..\Win32Project1\DLLHeader.h"
#ifdef _DEBUG
#pragma comment(lib, "../x64/Debug/Win32Project1.lib")
#else
#pragma comment(lib, "../x64/Release/Win32Project1.lib")
#endif
using namespace std;
// file_name:Source.cpp
#include "Header.h"
int main(int argc, char ** argv)
{
cout << add(10, 20) << endl;
return 0;
}
這里需要注意妇智,必須保證可以引用到DLLHeader.h文件和對應(yīng)的Win32Project1.lib文件。當運行可執(zhí)行程序時氏身,必須保證能夠訪問對應(yīng)Win32Project1.dll文件巍棱。至此,一個完整的DLL的編寫和引用就說完了蛋欣。
從上述的論述中航徙,我們可以發(fā)現(xiàn),編寫一個DLL是一件簡單的事情陷虎,編寫一個好的DLL的核心還是在如何編寫代碼這個環(huán)節(jié)到踏。C/C++對于DLL的接口的定義和使用都是顯而易懂的。
剩下的部分泻红,我想說下靜態(tài)庫和動態(tài)庫的概念夭禽。我們先說在windows的表現(xiàn)形式,在windows上動態(tài)庫的表現(xiàn)形式是:“*.dll, *.lib, *.h”谊路,這三個文件讹躯,使用方式在上面的例子中都說明了,重點強調(diào)一下可執(zhí)行程序運行時需要對應(yīng)的DLL庫文件(這是靜態(tài)庫和動態(tài)庫的本質(zhì)區(qū)別)缠劝。靜態(tài)庫的表現(xiàn)形式是:“*.lib, *.h”潮梯, 使用方式和上述例子相同,但是在可執(zhí)行程序運行時惨恭,我們并不需要對應(yīng)的LIB庫文件秉馏。
說說原因:靜態(tài)庫在程序鏈接的過程已經(jīng)將對應(yīng)的二進制帶碼寫入到了可執(zhí)行程序中,而動態(tài)庫是需要在程序運行時才會把對應(yīng)的二進制代碼調(diào)入內(nèi)存供可執(zhí)行程序調(diào)用(所以可執(zhí)行程序運行時脱羡,我們必須有對應(yīng)的DLL庫文件)萝究。
下面還有一個參考鏈接: Linux靜態(tài)庫和動態(tài)庫學(xué)習(xí)總結(jié)
我引用其中的一段話:
3.靜態(tài)庫和動態(tài)庫的比較
接靜態(tài)庫其實從某種意義上來說只不過它操作的對象是目標代碼而不是源碼而已。因為靜態(tài)庫被鏈接后庫就直接嵌入可執(zhí)行文件中了锉罐,這樣就帶來了兩個問題帆竹。
(1)首先就是系統(tǒng)空間被浪費了。這是顯而易見的脓规,想象一下栽连,如果多個程序鏈接了同一個庫,則每一個生成的可執(zhí)行文件就都會有一個庫的副本,必然會浪費系統(tǒng)空間秒紧。
(2)再者绢陌,一旦發(fā)現(xiàn)了庫中有bug,挽救起來就比較麻煩了熔恢。必須一一把鏈接該庫的程序找出來脐湾,然后重新編譯。
而動態(tài)庫的出現(xiàn)正彌補了靜態(tài)庫的以上弊端绩聘。因為動態(tài)庫是在程序運行時被鏈接的沥割,所以磁盤上只須保留一份副本,因此節(jié)約了磁盤空間凿菩。如果發(fā)現(xiàn)了bug或要升級也很簡單,只要用新的庫把原來的替換掉就行了帜讲。
但是靜態(tài)庫也有自己的優(yōu)點:
編譯后的執(zhí)行程序不需要外部的函數(shù)庫支持衅谷,因為所有使用的函數(shù)都已經(jīng)被編譯進去了。
靜態(tài)庫的名字一般是libxxx.a(Linux)
動態(tài)庫的名字一般是libxxx.so(Linux)似将,有時候也是 libxxx.so.major.minor获黔,xxxx是該lib的名稱,major是主版本號在验, minor是副版本號
linux系統(tǒng)有幾個重要的目錄存放相應(yīng)的函數(shù)庫玷氏,如/lib /usr/lib