C++檔案說明及使用方法

Tank4733發表於2020-11-19

C++檔案說明及使用方法

C++/C程式編譯的過程可以粗分為兩個階段:編譯和連結;編譯又可以分為 預處理、編譯、彙編三個階段
在這裡插入圖片描述
在編寫編譯C++的過程中有很多種檔案,例如原始檔,標頭檔案,靜態庫檔案,動態庫檔案等。每種型別的檔案都有其存在的意義

庫檔案

庫是一些函式和類的集合,其實現了某些特定的功能,是程式的開發免於從頭開始。
庫有兩種:靜態連結庫和動態連結庫!在windows下靜態連結庫為.lib,動態連結庫為.dll;Linux下靜態連結庫為.a,動態連結庫為.so。這裡我們只介紹Windows下的庫。

1. 特點

無論是靜態連結庫還是動態連結庫,都是庫檔案,是obj檔案的集合,都已經完成了編譯過程,它們的作用也是在經歷連結後生成可執行檔案。在我們的工程中,如果採用靜態連結庫(靜態編譯),工程在編譯時會匯出lib中的宣告和實現,並將所有程式碼都嵌入到宿主程式,生成最終的可執行檔案,釋出軟體時,只需要釋出exe檔案,不再需要.lib檔案;如果採用動態編譯庫(動態編譯),工程在編譯過程中只將庫中的宣告部分匯出,嵌入到程式碼中生成可執行檔案,再執行期間動態的去載入解除安裝.dll。釋出軟體時,由於可執行檔案的實現在dll中,所以dll必須與exe一起釋出。靜態連結庫不能再包含其它庫檔案,動態連結庫可以再包含其它庫檔案。

2.優缺點

靜態連結:佔用空間大,程式編譯完成後,移植性強;lib不能再包含其它庫,擴充套件性差;庫檔案升級時需要編譯整個工程,靈活性差。

動態連結:佔用空間小,庫方法更新只需要更換DLL,擴充套件性和靈活性強

3.靜態庫生成及使用方法

靜態連結庫生成方式:以建立test.lib為例

1.新建標頭檔案、原始檔

在建立的工程中,開啟解決方案資源管理器。在原始檔下建立test.cpp,標頭檔案下建立test.h,新增對應的程式碼。

2.配置屬性

在工程的屬性表中,修改配置屬性

  • 常規->專案預設值->配置型別:將配置型別設定為靜態庫(.lib)

3.排除工程中的main.cpp(包含main函式的入口檔案),生成

靜態連結庫匯入方式:

在專案的屬性表中,附加庫目錄和包含目錄,新增依賴項

  • C/C+±>常規->附加包含目錄:新增include目錄
  • 連結器->常規->附加庫目錄:新增lib目錄
  • 連結器->輸入->附加依賴項:新增 tinyxml.lib

4.動態庫生成及使用方法

DLL的分類有三種,Non-MFC DLL(非MFC DLL),MFC Regular(MFC規則DLL)和MFC Extension DLL(MFC擴充DLL)。

動態連結庫的生成方法:以Non-MFC DLL為例

1.新建一個應用程式型別為DLL的工程

開啟VS2015,新建一個VC++空專案,並將應用程式型別設定為DLL,如下:
在這裡插入圖片描述
工程建立好後,將平臺配置修改為Debug|X64

2.新增標頭檔案和原始檔

—在解決方案資源管理器中的標頭檔案下新增新專案test.h,程式碼如下—

#ifndef __TEST_H__
#define __TEST_H__
extern "C" int __declspec(dllexport) add(int num1, int num2);
#endif

標頭檔案中extern "C"是告訴編譯器該函式採用C呼叫方式進行編寫

__declspec(dllexport)是宣告函式add為dll的匯出函式,DLL的匯出函式是指可供呼叫dll的程式呼叫的函式;如果直接像靜態庫標頭檔案的呼叫方式:int add(int num1, int num2)則是DLL的內部函式,DLL內部函式只能用於DLL自身呼叫,不能供呼叫DLL的函式呼叫。

—在解決方案資源管理器中的原始檔下新增新專案test.cpp,程式碼如下—

#include "test.h"

int add(int num1, int num2) {
  return num1 + num2;
}

3.生成動態庫

右鍵解決方案下的TestDLL專案,生成。在工程(解決方案)的x64/Debug資料夾下生成了如下檔案,其中包含.lib和.dll
在這裡插入圖片描述

動態連結庫使用方法:

DLL檔案的呼叫方式有兩種,一種是顯式呼叫,一種是隱式呼叫。

—顯式呼叫—

1.在解決方案下新建一個控制檯應用專案,命名為TestUseDLL
在這裡插入圖片描述

2.呼叫函式

在TestUseDLL.cpp檔案中新增如下程式碼:

#include "stdafx.h"
#include "windows.h"
#include <iostream>
typedef int(*lpAddFun)(int num1, int num2);

int main()
{
  HINSTANCE hDLL;
  hDLL = LoadLibrary(L"TestDLL.dll");
  if (hDLL != NULL) {
    lpAddFun add = (lpAddFun)GetProcAddress(hDLL, "add");
    if (add != NULL) {
      int ret = add(4,5);
      std::cout << ret << std::endl;
    }
    FreeLibrary(hDLL);
  }
  system("Pause");
  return 0;
}


直接通過Windows自帶的LoadLibrary函式動態載入DLL模組,並將DLL模組控制程式碼賦給HINSTANCE控制程式碼物件,再通過Windows自帶的GetProcAddress函式得到DLL模組中指定函式名的函式指標,並賦值給函式指標add,使用add即可呼叫動態連結庫中的add。程式輸出如下:
在這裡插入圖片描述

—隱式呼叫—

1.將動態庫的標頭檔案,生成的lib檔案和dll檔案獨立打包,如下:
在這裡插入圖片描述
在新建一個控制檯應用專案,在專案的屬性表中,附加庫目錄和包含目錄,新增依賴項

  • C/C+±>常規->附加包含目錄:新增include目錄
  • 連結器->常規->附加庫目錄:新增lib目錄
  • 連結器->輸入->附加依賴項:新增 TestDLL.lib

2.設定DLL

工程中DLL的搜尋順序依次為(禁用安全DLL查詢模式):

  • 程式執行模組所在目錄
  • 當前目錄(程式開啟的目錄)
  • 系統目錄:\Windows\System32
  • Windows目錄:\Windows
  • 環境變數PATH中的目錄

DLL作為我們的資原始檔,一定需要被工程找到,我們通常將DLL與工程生成的可執行檔案.exe放在同一目錄,並一起釋出。

3.呼叫函式

在TestUseDLL.cpp檔案中新增如下程式碼:

#include "stdafx.h"
#include <iostream>
#include "test.h"

int main()
{
  int ret = add(4, 5);
  std::cout << ret << std::endl;
  system("Pause");
  return 0;
}

程式能夠正常輸出9

5.動態庫更新方法

這裡的更新有兩種:

1.單純實現方法的更新,標頭檔案未更新:直接替換DLL即可

2.增加新的方法,標頭檔案也更新:替換標頭檔案、.lib庫檔案以及.dll庫檔案

6.動態庫的跨語言使用
在這裡插入圖片描述

VS2015中匯入檔案說明

1.VC++目錄->包含目錄:新增include目錄

2.VC++目錄->庫目錄:新增lib目錄

3.C/C+±>常規->附加包含目錄:新增include目錄

4.連結器->常規->附加庫目錄:新增lib目錄

5.連結器->輸入->附加依賴項:新增 TestDLL.lib

上面的1和3都能將標頭檔案的include目錄加入到工程,但是區別在於,1中的包含目錄會修改系統的Include巨集的值,是全域性的,而3只針對當前專案,對其它專案沒有影響。2與4同理,2會影響全域性的庫,4只針對當前專案新增庫。5是使用的lib資料夾中的依賴項。

參考:

https://www.cnblogs.com/ganxiang/p/13206704.html

https://www.cnblogs.com/tiduswj/p/3716507.html

相關文章