中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++ 中的動態庫和靜態庫(Windows)

發布時間:2020-07-19 21:37:10 來源:網絡 閱讀:17247 作者:shangluyi 欄目:系統運維

庫:

在C/C++中,使用庫(Library)的技術,可以將編譯好的符號提供給第三方使用。

庫有兩種:

1、動態庫 Dynamic-Link Library (DLL)    (Linux下叫做 Shared Library)

2、靜態庫 Static Library


一、動態庫的創建和使用


創建DLL:

用VC創建一個類型為 “dll”的控制臺項目,VC會自動創建DLL的項目框架

它自動生成一個DllMain函數,可以類比普通應用程序中的main函數


VC項目設置:

1、取消“預編譯頭文件”

2、改為 “/MTd編譯”

3、修改輸出的DLL的名字 (my.dll)


C++ 中的動態庫和靜態庫(Windows)

C++ 中的動態庫和靜態庫(Windows)

C++ 中的動態庫和靜態庫(Windows)


編譯,得到 *.lib 和 *.dll,其中:

*.dll:

包含所有代碼編譯成的指令


*.lib:包含一個列表,表名my.dll中含有哪些符號,每個符號對應在dll中的位置。(被導出的符號)


所以,*.lib比*.dll的文件體積小得多





如果想導出一個全局函數,就用關鍵字 __declspec(dllexport)來聲明

注意:這是VC平臺特有的關鍵字,在linux平臺下不可用

使用如下:

template <typename T>
__declspec(dllexport) void MySwap(T& obj1, T& obj2)
{
	T tmp = obj1;
	obj1 = obj2;
	obj2 = tml;
}



使用dll:

#pragma  comment(lib, "12_18_DLL01")

__declspec(dllimport) int Add(int a, int b);

int main()
{
	int ret = Add(1, 2);
	std::cout << ret << std::endl;
	return 0;
}

但這個地方我發現了一個問題:

__declspec(dllimport) int Add(int a, int b);

這行代碼表示導入dll文件中的符號

但一開始我錯誤得寫成了 export, 結果居然仍然是正確的

沒有深究,初步推測是編譯器優化了 (IDE: VS2015),甚至不寫前面的關鍵字,直接寫成函數的聲明,程序也是能正確執行的


DLL的部署位置:

1、可執行文件所在目錄

2、進程當前目錄

3、系統目錄 (C:\Windows\System32\    和  C:\Windows\System\)

4、Windows目錄 (C:\Windows\)

5、環境變量 PATH 中的目錄



通過初步接觸DLL的發布和使用,相比普通的聲明、定義,會發現DLL有以下作用:

1、隱藏了代碼

2、公開了功能


當然,DLL的作用遠不止如此





二、DLL的加載和卸載


DLL的加載:

DLL不能獨立運行,只有當 *.exe 被運行時, *.dll 才會被加載運行。

在exe文件中有一些標識信息,表示該 exe 依賴哪些 dll 文件,操作系統據此去尋找、加載相應的dll文件。

exe 被加載到內存,形成一個進程 process,dll也被加載到內存,進程可以直接調用DLL中的函數(Code)


數據段和代碼段:

在dll文件中,至少分為兩個段:

1、代碼段:

存儲指令(函數體)

2、數據段:

數據段,存放全局變量

當 *.dll 被加載時,代碼段只被加載一次,是公共的。

數據段被每個程序各自拷貝一份,是私有的



三、DLL中的動態內存管理

在dll中申請的動態內存,必須在dll中釋放,否則會導致內存泄漏 (這是由Windows自己的特點決定的)



四、DLL中使用頭文件

按照慣例,由模塊的作者提供頭文件,頭文件中應該用類型、函數聲明。

所以,我們在創建DLL時,應該附帶一份頭文件,而不是讓使用者自己去寫函數聲明。


五、DLL中導出一個類

導出類的定義,其實就是導出其成員函數

類的聲明格式:

class __declspec(dllimport) MyClass
{};


六、靜態庫的概念及使用


靜態庫:

static library,僅一個 *.lib 文件

靜態庫中直接就含有代碼段和數據段,在鏈接過程中,是直接把里面的東西鏈接過來,形成完整的可執行程序

exe運行的時候不依賴 .lib 文件


創建:

1、建立一個新工程,工程類型為:靜態庫

2、不需要其他設置,直接編譯鏈接生成,得到 *.lib文件


使用:

#pragma comment(lib, "MyLib.lib")

int MyAdd(int a, int b);    //通常發布會把把聲明放到頭文件中,一并發布


靜態庫的注意事項:

1、靜態庫的使用不太方便:

如果該靜態庫是VS2008編譯的,那么APP也得用VS2008編譯,版本必須一致

此外,運行時庫(/MT、/MTd、/MD、/MDd)也必須要一致

因此可以看出,靜態庫的使用,約束條件是比較多的


靜態庫和動態庫的對比:

靜態庫優點:

使用靜態庫,最后得到的可執行程序執行時對這個庫不再依賴


動態庫優點:

便于升級更新,只要保持接口不變,可以通過更新DLL來升級程序,而不需要重新編譯程序


目前通常都使用動態庫


但動態庫也存在更多的安全方面的隱患,畢竟如果有人惡意替換DLL(能做到這一步的人往往是軟件團隊的內部人員),程序的執行將會違背編程者的本意.......


七、DLL的手動加載

之前加載DLL的方式是自動加載。

自動加載和手動加載:

1、自動加載

在編譯時指定dll,則當exe程序啟動運行時,首先加載相關的dll

(DLL在程序執行前被加載,在程序結束后被卸載)


2、手動加載

在編譯時不指定dll,在運行時調用LoadLibrary來加載dll 

(這樣做,可以自己決定什么時候加載、什么時候卸載DLL)



手動加載的方式:

#include <winsock2.h>
#include <windows.h>

使用 LoadLibrary 來加載dll,

使用 FreeLibrary 來卸載dll,

它提供了一種在運行時手動加載dll的技術手段,增加了編程的靈活性

(只要有*.dll就可以,也不需要 *.lib 和 *.h )


對DLL的要求:

1、要求待調用的函數按“C”方式編譯(符號名即函數名)

extern "C" __declspec(dllexprot) int MyAdd(int a, int b);

2、dll文件放在可被系統搜索到的路徑


代碼:

#include <iostream>
#include <winsock2.h>
#include <windows.h>

int main()
{
	wchar_t* Path = L"12_18_DLL01.dll";
	HINSTANCE  handle = LoadLibrary(Path);	// 字符集兼容問題
	if (handle)
	{
		// 定義要找的函數原型
		typedef int(*DLL_FUNCTION_ADD) (int, int);
		// 找到目標函數的地址	注意實現必須用 extern "C" 的方式編譯
		DLL_FUNCTION_ADD dll_func = (DLL_FUNCTION_ADD)GetProcAddress( handle, "Add");
		if (dll_func)
		{
			// 調用該函數
			int result = dll_func(1, 2);
			std::cout << result << std::endl;
		}
	}
	FreeLibrary(handle);
	return 0;
}


八、項目的靜態編譯

有一種場景,將以往VS生成的 *.exe 程序拷貝到其他 沒有VS運行環境的機器上,這時候程序往往是無法運行的,這是因為,VC編譯默認采用動態編譯的方式,因此 要么給這個機器也安裝一套運行環境,要么采用靜態編譯的方式生成可執行文件(*.exe)

靜態編譯后的程序,將會包含一切程序運行時所依賴的環境


對VC來說:

靜態編譯:

/MT  /MTd


動態編譯:

/MD  /MDd


C++ 中的動態庫和靜態庫(Windows)



動態編譯和靜態編譯的比較:

1、動態編譯不方便發布,但生成的可執行文件體積較小

2、靜態編譯方便發布,但生成的可執行文件體積較大



向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东乡族自治县| 长海县| 丘北县| 八宿县| 岳阳市| 长岭县| 阜平县| 水富县| 临邑县| 景泰县| 新民市| 临沭县| 莱州市| 江陵县| 康定县| 花莲县| 南郑县| 陇南市| 渭南市| 天柱县| 云浮市| 安溪县| 南和县| 道真| 上思县| 九江市| 阜平县| 宁安市| 昌江| 神农架林区| 化州市| 无为县| 志丹县| 萝北县| 阳江市| 孙吴县| 乳山市| 文山县| 广西| 舒兰市| 济南市|