天天看點

再談靜态庫和動态庫(C++)

文章目錄

      • 說明
      • 動态庫和靜态庫聯系與差別
      • 靜态庫(static lib)注意事項
      • 動态庫(dynamic lib + dll)注意事項
      • 常見問題
      • 聯系部落客

說明

  • 本文是在綜合CSDN部落格的基礎上,再加上部落客自己實踐總結所寫
  • 部落客之前曾寫過一篇博文介紹該内容,但那篇文章有囫囵吞棗之意,是以“再談”
  • 本文若有錯誤之處,請在評論留言,及時回複
  • 本文涉及到的環境均為 Windows 10 + VS 2013

動态庫和靜态庫聯系與差別

  • 這是部落客之前寫的一篇入門文章,可以結合的看
VS下靜态庫與動态庫的生成與使用
  • 其它相關文章,部落客推薦
static lib和dynamic lib
VS2013動态庫檔案的建立及其使用詳解
c++導出庫

靜态庫(static lib)注意事項

  • 建立靜态庫工程
    • 正常寫 .h 和 .cpp
  • 建立測試工程
    • 編輯 test.cpp
    • 将 .lib 複制到 test.cpp
    • 【屬性 - 連結器 - 附加依賴項】加入 .lib 名稱
    • 編譯運作

動态庫(dynamic lib + dll)注意事項

  • 建立動态庫生成工程 DLLGenerater
    • 選擇 控制台應用程式,其它請讀者自行嘗試,大同小異
    • 選擇 DLL
    • 勾選 空項目
    • 預編譯頭VS 預設強制勾選
    • 安全開發生命周期(SDL)檢查 選不選擇無所謂
  • 建立若幹 .h 和 .cpp,每個 .h 又可包括若幹内容
    • math.h 和 math.cpp 示例代碼(見文末所附代碼)
    • animal.h 和 animal.cpp 示例代碼(見文末所附代碼)
  • 不寫 main 函數
    • 如果想驗證代碼的正确性,可在屬性将預設類型的配置類型像彗星修改為**.exe**進行編譯運作
    • 編譯即可,在 …/Debug 或者 …/Release 目錄下生成 DLLGenerater.lib 和 DLLGenerater.dll
  • 建立測試動态庫工程 DLLUser
    • 建立 test.cpp
    • 複制 math.h 和 animal.h 到 test.cpp 同一級目錄
    • 複制 DLLGenerater.lib 和 DLLGenerater.dll 也到 test.cpp 同一級目錄
    • DLLUser 屬性的連結器的附加依賴項中添加 DLLGenerater.lib
    • 編輯 test.cpp 的内容(見文末所附代碼)
    • 編譯運作成功
  • 附:使用 DLLGenerater.dll 的幾種方式
    • 編譯運作時候
      • 第一種方式
        • .h、.lib、.dll、随 test.cpp 同一級目錄
      • 第二種方式
        • .h、.lib 随 test.cpp 同一級目錄
        • 系統環境變量的 system 的 path 加入 .dll 的路徑(Windows 下可能需要重新開機電腦)
      • 第三種方式
        • .h 随 test.cpp 同一級目錄
        • test.cpp 中加入

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

        • 系統環境變量的 system 的 path 加入 .dll 的路徑(Windows 下可能需要重新開機電腦)
      • 第四種方式(類似于配置第三方庫)
        • 【項目屬性 - VC++目錄 - 包含路徑】 添加 .h 路徑
        • 【項目屬性 - VC++目錄 - 包含庫目錄】 添加 .lib 路徑
        • 【項目屬性 - 連結器 - 附加依賴項】 寫入具體的 .lib 名稱
        • 系統環境變量的 system 的 path 加入 .dll 的路徑(Windows 下可能需要重新開機電腦)
    • 脫離VS運作時候
      • 第一種方式
        • 将 .dll 和 .exe 放在一起
      • 第二種方式(這個是我猜測的,未經實際驗證)
        • 預先就在檔案中寫入 .dll 的相對路徑,這樣的話可以在程式打包釋出時候将 .dll 放入指定檔案夾,具體可參見現有軟體的安裝程式(如參看 QQ 的安裝程式路徑)
  • 附:上述所提及代碼

math.h

#ifndef _MATH_H_
#define _MATH_H_

#include <cmath> // 記得加頭檔案

// 有時候覺得寫得麻煩
// 那麼可以 typadef
#ifndef MY_DLL // 條件編譯
#define MATH_EXPORT __declspec(dllexport)
#endif

// 對于函數(全局函數,成員函數等)
// __declspec(dllexport) 寫在最前面
// 然後是傳回值,函數名,形參
__declspec(dllexport) int add(int a, int b);

// 對于類,如果要導出所有函數
// 那麼 __declspec(dllexport) 寫在 class 和 類名中間
class __declspec(dllexport) ExportAllDll {
public:

    float getSin(float theta); // 普通成員函數
    static void printClass(); // 靜态函數

private:

    const double PI = std::acos(-1);

    // 私有函數,不會導出!!!并且該導出無實際意義
    float __getTan(float theta);

};

// 對于類,如果要導出部分函數
// 則類名前不加 __declspec(dllexport)
// 而是在要導出的函數前面加上 __declspec(dllexport)
class ExportPartDll {
public:

    __declspec(dllexport) float getSqrt(float num); // 導出
    float getAbs(float num); // 不導出
};

// 也可以這樣導出函數
MATH_EXPORT void getMatrix();

#endif // _MATH_H_
           

math.cpp

#include "math.h"
#include <iostream>

// .cpp 實作檔案一概不寫 __declspec(dllexport)
int add(int a, int b){
	return a + b;
}

// 類函數的實作記得加上類名
float ExportAllDll::getSin(float theta){
	return std::sinf(theta * PI / 180);
}

// 這裡不寫 static
void ExportAllDll::printClass(){
	std::cout << "printClass\n";
}

// 私有函數的實作
float __getTan(float theta){
	return 90.0f;
}

// 這個是要導出的函數
float ExportPartDll::getSqrt(float num){
	return std::sqrt(num);
}

// 這個不導出
float ExportPartDll::getAbs(float num){
	return std::abs(num);
}

// typedef __declspec(dllexport) MY_DLL 的使用
void getMatrix(){
	std::cout << "This is matrix.\n";
}
           

animal.h

#ifndef _ANIMAL_H_
#define _ANIMAL_H_

__declspec(dllexport) void printZoo();

#endif // _ANIMAL_H_
           

main.cpp

#include "animal.h"
#include <iostream>

void printZoo(){
	std::cout << "printZoo()\n";
}
           

test.cpp

#include "math.h"
#include "animal.h"
#include <iostream>

int main(){

	// 測試全局函數
	int a = 1, b = 2;
	std::cout << add(a, b) << std::endl;

	// 測試導出類
	ExportAllDll ad;
	std::cout << ad.getSin(30) <<std::endl;
	ExportAllDll::printClass();

	// 測試類導出函數
	ExportPartDll pd;
	std::cout << pd.getSqrt(9.0f) << std::endl;
	// std::cout << pd.getAbs(-6.6f) << std::endl;

	// 測試全局函數
	getMatrix();

	// 測試全局函數
	printZoo();

	return 0;
}
           

常見問題

C++ dll庫隻生成dll檔案,而未生成lib檔案的問題
Error LNK2001 無法解析的外部符号 的幾種情況及解決辦法

聯系部落客

評論會盡快回複