首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C/C++ 動態連結庫 (DLL) 建立與呼叫全攻略:隱式連結 vs 顯式連結

     編輯:關於C++

DLL 實現代碼複用、模組化部署與熱更新。本文以 Visual Studio 為例,完整示範非 MFC DLL 的建立、.def 匯出檔用法、隱式連結(靜態載入)與顯式連結(動態載入)兩種呼叫模式的專案設定、程式碼與優缺點對比。

一、建立 DLL 專案

  1. 專案類型:**Win32 Dynamic-Link Library** → 專案名 DllDemo。
  2. 新增 DllDemo.h 定義匯出巨集:
#ifdef DllDemo_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif

extern "C" {
    DLL_API int __stdcall Max(int a, int b); // __stdcall 便於跨語言呼叫
}
  1. DllDemo.cpp 實作:
#include "DllDemo.h"
DLL_API int __stdcall Max(int a, int b) {
    return (a > b) ? a : (a < b) ? b : 0; // 相等回傳 0
}
  1. 編譯產出 DllDemo.dll、DllDemo.lib、DllDemo.h。

二、.def 檔替代方案(無需 __declspec)

; DllDemo.def
LIBRARY MyDll
EXPORTS
    Max @1

專案屬性 → 連結器 → 輸入 → 模組定義檔 指向 DllDemo.def,重新編譯即可。

三、隱式連結(靜態載入)

  • 呼叫端專案複製 DllDemo.h、DllDemo.lib、DllDemo.dll。
  • 原始碼:
#include "DllDemo.h"
#pragma comment(lib, "DllDemo.lib") // 告訴連結器連結 .lib

int main() {
    int v = Max(2, 9); // 直接呼叫,像普通函式
    printf("Max = %d\n", v);
    return 0;
}
  • 優點:語法簡單、編譯期檢查型別、載入速度快。
  • 缺點:啟動時必須找到 DLL、版本耦合度高、無法延遲載入/條件載入。

四、顯式連結(動態載入)

  • 僅需 DllDemo.dll,不需 .lib/.h。
  • 步驟:
typedef int (__stdcall *LPMAX)(int, int); // 函式指標型別

HINSTANCE hDll = LoadLibrary(TEXT("DllDemo.dll"));
if (!hDll) return -1;

LPMAX pMax = (LPMAX)GetProcAddress(hDll, "Max"); // 或序數 MAKEINTRESOURCE(1)
if (pMax) {
    int v = pMax(2, 9);
    printf("Max = %d\n", v);
}
FreeLibrary(hDll);
  • 優點:可延遲/條件載入、支援插件架構、DLL 缺失不會讓主程式啟動失敗。
  • 缺點:無編譯期型別檢查、需手動管理函式指標、易寫錯裝飾名稱/呼叫慣例。

常見坑與避坑指南

問題原因解決
LNK2019 無法解析外部符號未連結 .lib 或 .def 匯出名稱不符檢查 dumpbin /exports DllDemo.dll 實際匯出名稱
呼叫慣例不符導致堆疊破壞DLL 用 __stdcall,呼叫端預設 __cdecl雙方統一宣告 __stdcall 或 WINAPI
C++ 名稱修飾導致 GetProcAddress 失敗未加 extern "C"DLL 標頭與實作皆包裹 extern "C"
Debug/Release CRT 不匹配DLL 與 EXE 連結不同版本 CRT統一專案屬性 → C/C++ → 代碼產生 → 執行階段程式庫
「隱式連結適合穩定內部介面,顯式連結適合插件/熱插拔;兩者常共存於同一專案不同模組。」
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved