上一章節:
十一、C++速通秘籍—多線程-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147055932?spm=1001.2014.3001.5502
本章節代碼:
cpp2/library · CuiQingCheng/cppstudy - 碼云 - 開源中國https://gitee.com/cuiqingcheng/cppstudy/tree/master/cpp2/library
目錄
上一章節:
本章節代碼:
一、編程后為什么會引入“庫”,什么是庫?
二、庫分為哪幾類? - 靜態庫,動態庫
1、靜態庫(.a 或.lib)
2、動態庫(.so 或.dll)
三、Linux/windows系統下的庫
1、Linux 下表現形式
2、Windows 下表現形式
四、Linux/Windows下使用靜態庫,什么場景下使用靜態庫?
1、適用場景
2、Linux 下創建和使用靜態庫
2.1、創建靜態庫
2.2、使用靜態庫
3、Windows 下創建和使用靜態庫
3.1、創建靜態庫
3.2、使用靜態庫
五、Linux/Windows下使用動態庫,什么場景下使用動態庫?
1、適用場景
2、Linux 下創建和使用動態庫
2.1、創建動態庫
2.1、使用動態庫
3、Windows 下創建和使用動態庫
3.1、創建動態庫
六、靜態庫,與動態庫二者的區別
內存占用
部署難度
運行效率
可維護性
七、總結
一、編程后為什么會引入“庫”,什么是庫?
????????想象一下你是一位超級大廚,每次做飯都要從頭開始種糧食、養牲畜、采摘蔬菜,那得花費多少時間和精力呀!在編程的世界里也是如此,如果每次編寫程序都要從頭開始實現一些常用的功能,比如文件讀寫、數學計算等,那程序員可就太累啦。于是,“庫”就應運而生了。
????????庫就像是一個裝滿各種工具的百寶箱,里面存放著已經編寫好的代碼,這些代碼實現了各種各樣的功能。當程序員需要使用某個功能時,不需要自己重新編寫代碼,只需要從這個百寶箱里拿出對應的工具(也就是調用庫中的代碼)就可以了。比如說,在 C++ 中,我們之前已經接觸過std標準庫,就提供了很多常用的功能,像字符串處理、容器管理等。你只需要包含相應的頭文件,就可以使用這些功能,就像大廚從廚房里拿出現成的調料一樣方便。
二、庫分為哪幾類? - 靜態庫,動態庫
庫主要分為兩類:靜態庫和動態庫,它們就像是兩種不同類型的百寶箱。
1、靜態庫(.a 或.lib)
????????靜態庫就像是一個可以被復制的百寶箱。當你使用靜態庫時,編譯器會把靜態庫中的代碼完整地復制到你的可執行文件中。這就好比你把百寶箱里的工具都拿出來,放進自己的口袋里,以后無論走到哪里,都可以隨時使用這些工具,不需要再依賴原來的百寶箱。
2、動態庫(.so 或.dll)
????????動態庫則像是一個共享的百寶箱,存放在一個公共的地方。當你的程序需要使用動態庫中的代碼時,程序會在運行時去這個公共的地方查找并加載所需的代碼。這就好比你需要某個工具時,不需要把整個百寶箱都拿走,只需要去公共的地方借用一下工具,用完后再還回去。
三、Linux/windows系統下的庫
1、Linux 下表現形式
在 Linux 系統中,靜態庫的文件擴展名通常是 `.a`,例如 `libexample.a`;動態庫的文件擴展名通常是 `.so`,例如 `libexample.so`。這些庫文件一般存放在 `/usr/lib` 或 `/usr/local/lib` 等目錄下。
2、Windows 下表現形式
在 Windows 系統中,靜態庫的文件擴展名是 `.lib`,例如 `example.lib`;動態庫的文件擴展名是 `.dll`,例如 `example.dll`。這些庫文件通常存放在系統目錄(如 `C:\Windows\System32`)或程序的安裝目錄下。
下面是一個簡單的對比圖:
系統 | 靜態庫擴展名 | 動態庫擴展名 |
Linux | .a | .so |
Windows | .lib | .dll |
四、Linux/Windows下使用靜態庫,什么場景下使用靜態庫?
1、適用場景
當你需要將程序打包成一個獨立的可執行文件,并且不希望依賴外部的庫文件時,就可以使用靜態庫。比如你開發了一個小型的游戲,希望用戶下載后可以直接運行,不需要額外安裝其他庫,這時就可以使用靜態庫。
2、Linux 下創建和使用靜態庫
2.1、創建靜態庫
假設我們有一個簡單的 C++ 函數 `add`,用于計算兩個整數的和,代碼如下:
add.cpp
int add(int a, int b)
{return a + b;
}
首先,將 `add.cpp` 編譯成目標文件:(add.o)
g++ -c add.cpp -o add.o
然后,使用 `ar` 工具將目標文件打包成靜態庫:
ar rcs libadd.a add.o
這樣,我們就創建了一個名為 `libadd.a` 的靜態庫。
2.2、使用靜態庫
現在,我們來編寫一個主程序 `main.cpp` 來使用這個靜態庫:
main.cpp
#include <iostream>// 聲明 add 函數
extern int add(int a, int b);int main() {int result = add(3, 5);std::cout << "3 + 5 = " << result << std::endl;return 0;
}
編譯并鏈接靜態庫:
g++ main.cpp -L. -ladd -o main
其中,`-L.` 表示在當前目錄下查找庫文件,`-ladd` 表示鏈接名為 `libadd.a` 的靜態庫。最后,運行可執行文件:
./main
3、Windows 下創建和使用靜態庫
3.1、創建靜態庫
同樣使用上面的 `add.cpp` 代碼,打開 VisualCode,創建一個 `add.cpp`文件。
代碼:
int addWin(int a, int b)
{return a + b;
}
這里編譯生成.lib,這里需要修改VsCode,中的tasks.json;
通過這個文件創建了兩個編譯任務:create_targe_file/create_static_lib
{"tasks": [{ // 生成目標文件"type": "shell","label": "create_target_file","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c","${file}","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"options": {"cwd": "${fileDirname}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true}},{ // 生成靜態庫"label": "create_static_lib","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\ar.exe","args": ["rcs","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.lib","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"}],"version": "2.0.0"
}
(1)、打開命令面板(Ctrl+Shift+P)
(2)、輸入?Tasks: Run Task?并選擇?create_target_file
(3)、創建靜態庫,跟步驟2相同選擇create_static_lib
3.2、使用靜態庫
創建一個staticEx.cpp
// 鏈接靜態庫
#include <iostream>// 聲明 addWin 函數
extern "C" int addWin(int a, int b);int main() {int result = addWin(5, 5);std::cout << "5 + 5 = " << result << std::endl;return 0;
}
配置tasks.json:
{"tasks": [{ // 生成目標文件"type": "shell","label": "create_target_file","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c","${file}","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"options": {"cwd": "${fileDirname}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true}},{ // 生成靜態庫"label": "create_static_lib","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\ar.exe","args": ["rcs","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.lib","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"},{ // 生成可執行文件"label": "create_exe_file","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c", // 編譯參數"${file}","-L${fileDirname}\\..\\..\\build","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.exe","-static"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"}],"version": "2.0.0"
}
五、Linux/Windows下使用動態庫,什么場景下使用動態庫?
1、適用場景
當多個程序需要共享相同的代碼,或者庫文件需要經常更新時,使用動態庫就非常合適。比如操作系統中的一些公共庫,多個程序都可以使用這些庫中的功能,這樣可以節省系統資源。
2、Linux 下創建和使用動態庫
2.1、創建動態庫
還是使用上面的 `add.cpp` 代碼,將其編譯成動態庫:
g++ -fPIC -c add.cpp -o add.o
g++ -shared -o libadd.so add.o
其中,`-fPIC` 選項用于生成位置無關代碼,`-shared` 選項用于創建動態庫。
2.1、使用動態庫
編寫主程序 `main.cpp`:
// main.cpp
#include <iostream>// 聲明 add 函數
extern int add(int a, int b);int main() {int result = add(9, 8);std::cout << "9 + 8 = " << result << std::endl;return 0;
}
編譯并鏈接動態庫:
g++ main.cpp -L. -ladd -o mainso
運行程序前,需要設置動態庫的搜索路徑:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./main
3、Windows 下創建和使用動態庫
3.1、創建動態庫
在 VsCode 中創建兩個文件`dyAdd.h/dyAdd.cpp`, 在dyAdd.h中添加一個導出函數的聲明,dyAdd.cpp中實現函數功能:
dyAdd.h
// 動態庫
#ifndef _DYADD_H_
#define _DYADD_H_#ifdef DYADD_DLL_EXPORTS
#define DYADD_API __declspec(dllimport)
#else
#define DYADD_API __declspec(dllexport) // 導出
#endifextern "C" DYADD_API int add(int a, int b);#endif
dyAdd.cpp
#include "dyAdd.h"extern "C" DYADD_API int add(int a, int b)
{return a + b;
}
tasks.json
{"tasks": [{ // 生成目標文件"type": "shell","label": "create_target_file","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c","${file}","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o","-DDYADD_EXPORTS" // 添加此行以定義 DYADD_EXPORTS 宏],"options": {"cwd": "${fileDirname}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true}},{ // 生成動態庫"label": "create_dynamic_lib","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-g","-shared","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.dll"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"},{ // 通過動態庫生成可執行文件"label": "create_exe_dyfile","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-g","${file}","-I${fileDirname}","-L${fileDirname}\\..\\..\\build","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.exe","-ladd"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"}],"version": "2.0.0"
}
這里第一步,第二步,執行后生成了dyAdd.dll,以及編譯的中間文件dyAll.o,編譯方法都是通過控制面板按步驟生成:
使用動態庫
dynamicEx.cpp
#include <iostream>
#include <windows.h>// 動態加載
typedef int (*AddFunction)(int, int);int main() {HINSTANCE hDLL = LoadLibrary("dyAdd.dll");if (hDLL != NULL) {AddFunction add = (AddFunction)GetProcAddress(hDLL, "add");if (add != NULL) {int result = add(3, 5);std::cout << "3 + 5 = " << result << std::endl;}else {std::cout << "Failed to get add function address." << std::endl;}FreeLibrary(hDLL);}return 0;
}
編譯并運行程序
六、靜態庫,與動態庫二者的區別
內存占用
靜態庫會將代碼復制到可執行文件中,導致可執行文件體積較大,占用更多的磁盤空間;而動態庫在多個程序間共享,只需要在內存中加載一份,節省了磁盤空間和內存資源。
部署難度
靜態庫部署簡單,可執行文件不依賴外部庫文件,用戶只需要運行可執行文件即可;動態庫部署時需要確保庫文件存在于系統的指定路徑中,否則程序可能無法正常運行。
運行效率
靜態庫的代碼在編譯時就已經鏈接到可執行文件中,運行時無需額外加載,效率相對較高;動態庫在運行時需要加載,會有一定的性能開銷。
可維護性
如果庫文件需要更新,使用靜態庫的程序需要重新編譯;而使用動態庫的程序只需要替換庫文件即可,不需要重新編譯。
下面是一個對比表格:
比較項 | 靜態庫 | 動態庫 |
內存占用 | 大 | 小 |
部署難度 | 簡單 | 復雜 |
運行效率 | 高 | 低 |
可維護性 | 低 | 高 |
七、總結
????????掌握靜態庫和動態庫的使用,能讓你的 C++ 編程之路更加順暢,就像大廚擁有了得心應手的工具,做出更加美味的菜肴一樣!希望通過這篇博客,你能對靜態庫和動態庫有更深入的理解。