1. 程式人生 > >靜態鏈接庫和動態鏈接庫

靜態鏈接庫和動態鏈接庫

pro 成員 ostream 指令 num n) else .com 需要

靜態鏈接庫和動態鏈接庫

共有兩種庫:

一種是LIB包含了函數所在的DLL文件和文件中函數位置的信息(入口),代碼由運行時加載在進程空間中的DLL提供,稱為動態鏈接庫dynamic link library。

一種是LIB包含函數代碼本身,在編譯時直接將代碼加入程序當中,稱為靜態鏈接庫static link library。

共有兩種鏈接方式:

動態鏈接使用動態鏈接庫,允許可執行模塊(.dll文件或.exe文件)僅包含在運行時定位DLL函數的可執行代碼所需的信息。

靜態鏈接使用靜態鏈接庫,鏈接器從靜態鏈接庫LIB獲取所有被引用函數,並將庫同代碼一起放到可執行文件中。

關於lib和dll的區別如下:

(1)lib是編譯時用到的,dll是運行時用到的。如果要完成源代碼的編譯,只需要lib;如果要使動態鏈接的程序運行起來,只需要dll。

(2)如果有dll文件,那麽lib一般是一些索引信息,記錄了dll中函數的入口和位置,dll中是函數的具體內容;如果只有lib文件,那麽這個lib文件是靜態編譯出來的,索引和實現都在其中。使用靜態編譯的lib文件,在運行程序時不需要再掛動態庫,缺點是導致應用程序比較大,而且失去了動態庫的靈活性,發布新版本時要發布新的應用程序才行。

(3)動態鏈接的情況下,有兩個文件:一個是LIB文件,一個是DLL文件。LIB包含被DLL導出的函數名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件鏈接到DLL文件。在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中相應函數代碼的地址,從而節省了內存資源。DLL和LIB文件必須隨應用程序一起發行,否則應用程序會產生錯誤。如果不想用lib文件或者沒有lib文件,可以用WIN32 API函數LoadLibrary、GetProcAddress裝載。

編譯生成LIB

創建win32控制臺程序,勾選LIB類型。增加並編寫app,生成解決方案

1>------ 已啟動生成:  項目: test, 配置: Debug Win32 ------
1>  test.cpp
1>  test.vcxproj -> D:\visual studio\test\Debug\test.lib
========== 生成:  成功 1 個,失敗 0 個,最新 0 個,跳過 0 個 ==========

編譯生成DLL:

創建win32控制臺程序,勾選DLL類型,創建add.h

#ifndef __ADD_H__
#define __ADD_H__
extern
"C" int _declspec(dllexport) add(int x, int y); #endif

這裏註意:使用 _declspec(dllexport) 關鍵字從 DLL 導出數據、函數、類或類成員函數。_declspec(dllexport) 會將導出指令添加到對象文件中,如果不適用dllexport,則動態使用dll的時候找不到函數

創建add.cpp

#include "add.h"
int add(int a, int b)
{
    return a + b;
}

然後點擊生成---生成解決方案,會在工程的Debug目錄下生成一個DLL文件(add.dll)

1> add.vcxproj -> D:\visual studio\add\Debug\add.dll
動態調用DLL(僅需要DLL,不需要頭文件和LIB)
#include <iostream>
#include <windows.h>
using namespace std;
typedef int(*FUN)(int, int);//定義指向和DLL中相同的函數原型指針
int main() 
{
    int x, y;
    HMODULE hDLL = LoadLibrary("D:\\visual studio\\add\\Debug\\add.dll");//加載dll
    if (hDLL != NULL)
    {
        FUN add = FUN(GetProcAddress(hDLL, "add"));//獲取導入到應用程序中的函數指針,根據方法名取得
        if (add != NULL)
        {
            cout << "Input 2 Numbers:";
            cin >> x >> y;
            cout << add(x, y) <<endl;
        }
        else
        {
            cout << "Cannot Find Function"  << endl;
        }
        FreeLibrary(hDLL);
    }
    else
    {
        cout << "Cannot Find dll"  << endl;
    }
    return 1;
}

生成結果:

Input 2 Numbers:3 4
7
請按任意鍵繼續. . .

靜態調用(同時需要頭文件、LIB和DLL文件,缺一不可)

1:將dll工程下的dll和lib拷貝到測試工程中的debug文件夾

2:編寫測試工程的頭文件

#ifndef __USEDll_H__
#define __USEDll_H__
extern "C" _declspec(dllimport) int add(int x, int y);
#endif

3:編寫cpp文件

#include "UseDll.h"
#include <iostream>
using namespace std;
#pragma comment(lib,"D:\\visual studio\\UseDll\\Debug\\add.lib")
int main()
{
    int x, y;
    cout << "Input 2 Numbers:";
    cin >> x >> y;
    cout << add(x, y) <<endl;
}

運行結果如下:

Input 2 Numbers:10 10
20
請按任意鍵繼續. . .

說明:#pragma comment (lib,"...lib")就是告訴鏈接器優先鏈接該lib文件,除了使用此語句外,可以在工程屬性-->鏈接器--> 輸入-->附加依賴項中添加此lib。此時該lib需要放到系統路徑下。

這裏註意,這裏的lib是生成dll的時候生成的,相對於生成lib時候產生的lib要小,其實這種是導入庫,並不是靜態庫,靜態庫本身就包含了實際執行代碼、符號表等等,而對於導入庫而言,其實際的執行代碼位於動態庫中,導入庫只包含了地址符號表,各個函數地址等等,確保程序找到對應函數的一些基本地址信息。

參考文檔:https://blog.csdn.net/red10057/article/details/7394213

https://blog.csdn.net/Sya_inn/article/details/53981440

http://www.cppblog.com/amazon/archive/2009/09/04/95318.html

靜態鏈接庫和動態鏈接庫