C 靜態庫與動態庫

2021-07-15 03:54:47 字數 3888 閱讀 6020

庫是寫好的現有的,成熟的,可以復用的**。現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的**都從零開始,因此庫的存在意義非同尋常。

本質上來說庫是一種可執行**的二進位制形式,可以被作業系統載入記憶體執行。庫有兩種:靜態庫(.a、.lib)和動態庫(.so、.dll)。

所謂靜態、動態是指鏈結。回顧一下,將乙個程式編譯成可執行程式的步驟:

之所以成為【靜態庫】,是因為在鏈結階段,會將彙編生成的目標檔案.o與引用到的庫一起鏈結打包到可執行檔案中。因此對應的鏈結方式稱為靜態鏈結。

試想一下,靜態庫與彙編生成的目標檔案一起鏈結為可執行檔案,那麼靜態庫必定跟.o檔案格式相似。其實乙個靜態庫可以簡單看成是一組目標檔案(.o/.obj檔案)的集合,即很多目標檔案經過壓縮打包後形成的乙個檔案。靜態庫特點總結:

下面編寫一些簡單的四則運算c++類,將其編譯成靜態庫給他人用,標頭檔案如下所示:

標頭檔案

#pragma once

class staticmath

;

linux下使用ar工具、windows下vs使用lib.exe,將目標檔案壓縮到一起,並且對其進行編號和索引,以便於查詢和檢索。一般建立靜態庫的步驟如圖所示:

1. linux靜態庫命名規則

linux靜態庫命名規範,必須是」lib[your_library_name].a」:lib為字首,中間是靜態庫名,擴充套件名為.a。

2. 建立靜態庫(.a)

通過上面的流程可以知道,linux建立靜態庫過程如下:

g++ -c staticmath.cpp

注意帶引數-c,否則直接編譯為可執行檔案

ar -crv libstaticmath.a staticmath.o

生成靜態庫libstaticmath.a。

大一點的專案會編寫makefile檔案(cmake等等工程管理工具)來生成靜態庫,輸入多個命令太麻煩了。

3. 使用靜態庫

編寫使用上面建立的靜態庫的測試**:

#include "staticmath.h"

#include

using

namespace

std;

int main(int argc, char* argv)

linux下使用靜態庫,只需要在編譯的時候,指定靜態庫的搜尋路徑(-l選項)、指定靜態庫名(不需要lib字首和.a字尾,-l選項)。

通過上面的介紹發現靜態庫,容易使用和理解,也達到了**復用的目的,那為什麼還需要動態庫呢?

為什麼還需要動態庫?

為什麼需要動態庫,其實也是靜態庫的特點導致。

動態庫在程式編譯時並不會被連線到目標**中,而是在程式執行是才被載入。不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有乙份該共享庫的例項,規避了空間浪費問題。動態庫在程式執行是才被載入,也解決了靜態庫對程式的更新、部署和發布頁會帶來麻煩。使用者只需要更新動態庫即可,增量更新。

動態庫特點總結:

window與linux執行檔案格式不同,在建立動態庫的時候有一些差異。

與建立靜態庫不同的是,不需要打包工具(ar、lib.exe),直接使用編譯器即可建立動態庫。

1. linux動態庫的命名規則

動態鏈結庫的名字形式為 lib***.so,字首是lib,字尾名為「.so」。

2. 建立動態庫(.so)

編寫四則運算動態庫**:

標頭檔案

#pragma once

class dynamicmath

;

g++ -fpic -c dynamicmath.cpp

-fpic 建立與位址無關的編譯程式(pic,position independent code),是為了能夠在多個應用程式間共享。

g++ -shared -o libdynmath.so dynamicmath.o

-shared指定生成動態鏈結庫。

其實上面兩個步驟可以合併為乙個命令:

g++ -fpic -shared -o libdynmath.so dynamicmath.cpp

3. 使用動態庫編寫使用動態庫的測試**:

#include "../dynamiclibrary/dynamicmath.h"

#include

using

namespace

std;

int main(int argc, char* argv)

引用動態庫編譯成可執行檔案(跟靜態庫方式一樣):

g++ testdynamiclibrary.cpp -l ../dynamiclibrary -ldynmath

然後執行:./a.out,發現竟然報錯了

發現還是報錯!那麼,在執行的時候是如何定位共享庫檔案的呢?

1) 當系統載入可執行**時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑。此時就需要系統動態載入器(dynamic linker/loader)。

2) 對於elf格式的可執行程式,是由ld-linux.so*來完成的,它先後搜尋elf檔案的 dt_rpath段—環境變數ld_library_path—/etc/ld.so.cache檔案列表—/lib/,/usr/lib 目錄找到庫檔案後將其載入記憶體。

如何讓系統能夠找到它:

我們將建立的動態庫複製到/usr/lib下面,然後執行測試程式。

二者的不同點在於**被載入的時刻不同

動態庫的好處是,不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有乙份該共享庫的例項。帶來好處的同時,也會有問題!如經典的dll hell問題,關於如何規避動態庫管理問題,可以自行查詢相關資料。

C 靜態庫與動態庫

感覺比較形象,就摘過來了.這次分享的 宗旨是 讓大家學會建立與使用靜態庫 動態庫,知道靜態庫與動態庫的區別,知道使用的時候如何選擇。這裡不深入介紹靜態庫 動態庫的底層格式,記憶體布局等,有興趣的同學,推薦一本書 程式設計師的自我修養 鏈結 裝載與庫 庫是寫好的現有的,成熟的,可以復用的 現實中每個程...

c 靜態庫與動態庫

庫分為靜態庫,動態庫,在不同系統下字尾不同。2.1.1 在鏈結和執行階段都涉及庫的呼叫 訪問 h檔案 標頭檔案 是庫的介面。h檔案提供給庫的使用者,使用者通過.h來呼叫庫中的api。2.1.2 庫中包含的是函式的實現 一堆函式的實現 這些函式在編寫的時候同樣要包含1中的標頭檔案,然後生成庫。2.1....

C 靜態庫與動態庫

1.靜態庫 1.靜態庫實際上就是一些目標檔案 一般以.o結尾 的集合,靜態庫一般以.a結尾,只用於生成可執行檔案階段。2.在鏈結步驟中,鏈結器將從庫檔案取得所需 複製到生成的可執行檔案中。這種庫稱為靜態庫。其特點是 可執行檔案中包含了庫 的乙份完整拷貝,在編譯過程中被引導程式中。缺點就是多次使用就會...