DLL庫的編寫(匯出 匯入)與使用

2021-07-11 06:27:09 字數 3472 閱讀 9399

dll庫的編寫(匯出、匯入)與使用

(1) 編寫dll時,為什麼用extern 「c」:

因為c和c++的重新命名規則是不一樣的。這種重新命名稱為「name-mangling」。據說,c++標準並沒有規定name-mangling的方案,所以不同編譯器使用的是不同的,例如:borland c++跟microsoft c++就不同,而且可能不同版本的編譯器他們的name-mangling

規則也是不同的。這樣的話,不同編譯器編譯出來的目標檔案.obj 是不通用的,因為同乙個函式,使用不同的name-mangling在obj檔案中就會有不同的名字。如果dll裡的函式重新命名規則跟dll的使用者採用的重新命名規則不一致,那就會找不到這個函式。

c標準規定了c語言name-mangling的規範。這樣就使得,任何乙個支援c語言的編譯器,它編譯出來的obj檔案可以共享,鏈結成可執行檔案。這是一種標準,如果dll跟其使用者都採用這種約定,那麼就可以解決函式重新命名規則不一致導致的錯誤。

影響符號名的除了c++和c的區別、編譯器的區別之外,還要考慮呼叫約定導致的name mangling。如extern 「c」_stdcall的呼叫方式就會在原來函式名上加上表示引數的符號,而extern 「c」_cdecl則不會附加額外的符號。

dll中的函式在被呼叫時是以函式名或函式編號的方式被索引的。

所以綜上。若採用某編譯器的c++的name-mangling方式產生的dll檔案可能不通用。因為它們的函式名重新命名方式不同。為了使得dll可以通用些,很多時候都要使用c的name-mangling方式,即是對每乙個匯出函式宣告為extern 「c」,而且採用_stdcall呼叫約定,接著還需要對匯出函式進行重新命名,以便匯出不加修飾的函式名。

注意到extern 「c」的作用是為了解決函式符號名的問題,這對於動態鏈結庫的製造者和動態鏈結庫的使用者都需要遵守的規則。但extern "c"只解決了c和c++語言之間呼叫的問題(extern 「c」是告訴編譯器,讓它按c的方式編譯),它只能用於匯出全域性函式這種情況而不能匯出乙個類的成員函式。

(2)_declspec(dllexport)和_declspec(dllimport)的作用:

_declspec還有另外的用途,這裡只討論跟dll相關的使用。正如括號裡的關鍵字一樣,匯出和匯入。

因為dll中必須說明函式要用於匯出,所以_declspec(dllexport)很有必要。但是可以換一種方式,可以使用def檔案來說明哪些函式用於匯出,同時def檔案裡邊還有函式的編號。而使用

_declspec(dllimport)卻不是必須的,但是建議這麼做。因為如果不用_declspec(dllimport)來說明該函式是從dll匯入的,那麼編譯器就不知道這個函式到底在**,生成的exe裡會有乙個call xx的指令,這個xx是乙個常數字址,xx位址處是乙個jmp dword ptr[***x]的指令,跳轉到該函式的函式體處【可理解為先到乙個函式表裡找到具體的函式體位址,然後跳轉到該位址執行】,顯然這樣就無緣無故多了一次中間的跳轉。如果使用了_declspec(dllimport)來說明,那麼就直接產生call dword ptr[***],這樣就不會有多餘的跳轉了。

(3)_sdtcall: 這是一種函式的呼叫方式。預設情況下vc使用的是_cdecl的函式呼叫方式,如果產生的dll只會給c/c++程式使用,那麼就沒必要定義為_stdcall呼叫方式,如果要給win32彙編使用(或者其他的_stdcall呼叫方式的程式),那麼就應該使用_stdcall。這個可能不是很重要,因為可以自己在呼叫函式的時候可以設定函式呼叫的規則。像vc就可以設定函式的呼叫方式,所以可以方便的使用win32彙編產生的dll。不過

_stdcall這呼叫約定會name-mangling

,所以我覺得用vc預設的呼叫約定簡便些。但是,如果既要_stdcall呼叫約定,又要函式名不給修飾,那可以使用*.def檔案,或者在**裡#pragma的方式給函式提供別名(這種方式需要知道修飾後的函式名是什麼)。

舉例:·extern 「c」_declspec(dllexport) bool  _stdcall cswuyg();

·extern 「c」_declspec(dllimport) bool  _stdcall cswuyg();

·#pragma comment(linker,"/export:cswuyg=_cswuyg@0")

(4).def檔案的規則為:

①library語句說明.def檔案相應的dll;

②exports語句後列出要匯出函式的名稱。可以在.def檔案中的匯出函式名後加@n,表示要匯出函式的序號為n(在進行函式呼叫時,這個序號將發揮其作用);

③.def 檔案中的注釋由每個注釋行開始處的分號(;) 指定,且注釋不能與語句共享一行。

*.def

檔案只負責修改函式名稱,不負責呼叫約定。

舉例

def檔案格式:

library  xx(dll名稱這個並不是必須的,但必須確保跟生成的

dll名稱一樣

)exports

[

函式別名

]=[函式名

](要匯出的函式

) @ [

函式序號

]如果把*.def

手動的在

link

新增:

1)工程的

properties

→configuration properties

→linker

→command line

→在「additional options」裡加上:

/def:[

完整檔名

].def 2

)工程的

properties

→configuration properties

→linker

→input

→module definition file 裡加上

[完整檔名

找dll

的順序是

1)程序的當前目錄;2)

windows

目錄下的系統目錄是

c:/windows/system32;3

)windows

目錄;4

)path

環境變數中列出的目錄

svn庫匯出與匯入

匯出 svnadmin dump c svnroot repos1 c svnbak repos1.dump 引數1 庫路徑 引數2匯出檔案路徑 匯入到乙個已存在的版本庫中的某一子資料夾下 cd www mkdir yhc svn add yhc svn commit m svnadmin load...

使用mysql dump 匯入與匯出的方法

mysql實用命令 wikipedia,自由的百科全書 一 連線mysql 格式 mysql h主機位址 u使用者名稱 p使用者密碼 1 例1 連線到本機上的mysql 首先在開啟dos視窗,然後進入mysql安裝目錄下的bin目錄下,例如 d mysql bin,再鍵入命令mysql uroot ...

Oracle資料庫的匯入與匯出

oracle資料庫的匯出可以分為邏輯備份和物理備份 而邏輯備份分為三種模式 1 使用者模式 匯出使用者所有物件以及物件中的資料 2 表模式 匯出使用者所有表或者指定表 3 整個資料庫 匯出資料庫中的所有物件 而匯出方式的備份有三種型別 1 完全型 complete export 備份整個資料庫 匯入...