溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

linux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些

發(fā)布時(shí)間:2023-02-07 10:03:53 來源:億速云 閱讀:98 作者:iii 欄目:建站服務(wù)器

這篇文章主要講解了“l(fā)inux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“l(fā)inux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些”吧!

區(qū)別:1、動(dòng)態(tài)庫的后綴為“.so”,靜態(tài)庫的后綴為“.a”。2、如果靜態(tài)函數(shù)庫改變了,那么程序必須重新編譯;而動(dòng)態(tài)函數(shù)庫的改變并不影響程序。3、相對(duì)于靜態(tài)庫,動(dòng)態(tài)庫在編譯的時(shí)候并沒有被編譯進(jìn)目標(biāo)代碼中,用戶的程序執(zhí)行到相關(guān)函數(shù)時(shí)才調(diào)用該函數(shù)庫里的相應(yīng)函數(shù),因此動(dòng)態(tài)函數(shù)庫所產(chǎn)生的可執(zhí)行文件比較小。

一、庫的基礎(chǔ)概念:

在windows平臺(tái)和linux平臺(tái)下都大量存在著庫。本質(zhì)上來說庫是一種可執(zhí)行代碼的二進(jìn)制形式,可以被操作系統(tǒng)載入內(nèi)存執(zhí)行。由于windows和linux的本質(zhì)不同,因此二者庫的二進(jìn)制是不兼容的。通俗的說就是把這些常用函數(shù)的目標(biāo)文件打包在一起,提供相應(yīng)函數(shù)的接口,便于程序員使用。在使用函數(shù)時(shí),只需要包對(duì)應(yīng)的頭文件即可。按照庫的使用方式又可分為動(dòng)態(tài)庫和靜態(tài)庫,在不同平臺(tái)下對(duì)應(yīng)后綴也有所不同。

WINDOWS下:.dll 后綴為動(dòng)態(tài)庫,.lib 后綴為靜態(tài)庫;

LINUX下:.so后綴為動(dòng)態(tài)庫,.a后綴為靜態(tài)庫。

二、靜態(tài)庫與靜態(tài)鏈接

<1>靜態(tài)庫:

靜態(tài)庫可以簡單的看成一組目標(biāo)文件的集合,即很多目標(biāo)文件經(jīng)過壓縮打包后形成的文件。比如在我們?nèi)粘>幊讨?,如果需要使用printf函數(shù),就需要包stdio.h的庫文件,使用strlen時(shí),又需要包string.h的庫文件,可是如果直接把對(duì)應(yīng)函數(shù)源碼編譯后形成的.o文件直接提供給我們,將會(huì)對(duì)我們的管理和使用上造成極大不便,于是可以使用“ar”壓縮程序?qū)⑦@些目標(biāo)文件壓縮在一起,形成libx.a靜態(tài)庫文件。

注:靜態(tài)庫命名格式:lib + "庫名稱”+ .a(后綴) 例:libadd.a就是一個(gè)叫add的靜態(tài)庫

<2>靜態(tài)鏈接:

對(duì)于靜態(tài)庫,程序在編譯鏈接時(shí),將庫的代碼鏈接到可執(zhí)行文件中,程序運(yùn)行時(shí)不再需要靜態(tài)庫。在使用過程中只需要將庫和我們的程序編譯后的文件鏈接在一起就可形成一個(gè)可執(zhí)行文件。

通過一個(gè)例子來了解下如何將我們自己寫的頭文件和代碼同時(shí)進(jìn)行編譯鏈接,最終生成可執(zhí)行文件:

/main.c/

#include <stdio.h>
#include "add.h"

int main()
{
	int ret = add(3, 4);
	printf("3 + 4 = %d\n",ret);

	return 0;
}

/add.c/

#include "add.h"

int add( int x, int y)
{	
	return x + y;
}


/add.h/

#pragma once
#include <stdio.h>

int add( int x, int y);

/Makefile/

main : main.c libadd.a
	gcc main.c -L . -ladd -o main
	//-L為指定路徑 .為當(dāng)前目錄下 -l+庫名字,編譯器可在指定目錄下自己尋找名為add的庫文件
	
libadd.a : 
	gcc -c add.c -o add.o
	
	//ar -rc將多個(gè)編譯后的文件打包為一個(gè)靜態(tài)庫文件
	ar -rc libadd.a add.o

.PHONY:clean
clean:
	rm main libadd.a

make后輸出截圖:

linux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些

<3>缺點(diǎn):

1、內(nèi)存和磁盤空間浪費(fèi):靜態(tài)鏈接方式對(duì)于計(jì)算機(jī)內(nèi)存和磁盤的空間浪費(fèi)十分嚴(yán)重。

假如一個(gè)c語言的靜態(tài)庫大小為1MB,系統(tǒng)中有100個(gè)需要使用到該庫文件,采用靜態(tài)鏈接的話,就要浪費(fèi)進(jìn)100M的內(nèi)存,若數(shù)量再大,那浪費(fèi)的也就更多。例如下圖:程序1和程序2都需要用到Lib.o,采用靜態(tài)鏈接的話,那么物理內(nèi)存中就會(huì)存放兩份對(duì)應(yīng)此文件的拷貝。

linux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些

2、更新麻煩:

比如一個(gè)程序20個(gè)模塊,每個(gè)模塊只有1MB,那么每次更新任何一個(gè)模塊,用戶都得重新下載20M的程序。

三、動(dòng)態(tài)庫與動(dòng)態(tài)鏈接

<1>動(dòng)態(tài)庫:

程序在運(yùn)行時(shí)才去鏈接動(dòng)態(tài)庫的代碼,多個(gè)程序共享庫的代碼。一個(gè)與動(dòng)態(tài)庫鏈接的可執(zhí)行文件僅僅包含它用到的函數(shù)入口地址的一個(gè)表,而不是外部函數(shù)所在目標(biāo)文件的整個(gè)機(jī)器碼。

注:動(dòng)態(tài)庫命名格式:lib + "庫名稱”+ .so(后綴) 例:libadd.so就是一個(gè)叫add的動(dòng)態(tài)庫

<2>動(dòng)態(tài)鏈接:

由于靜態(tài)鏈接具有浪費(fèi)內(nèi)存和模塊更新困難等問題,提出了動(dòng)態(tài)鏈接?;緦?shí)現(xiàn)思想是把程序按照模塊拆分成各個(gè)相對(duì)獨(dú)立部分,在程序運(yùn)行時(shí)才將他們鏈接在一起形成一個(gè)完整的程序,而不是像靜態(tài)鏈接那樣把所有的程序模塊都鏈接成一個(gè)單獨(dú)的可執(zhí)行文件。所以動(dòng)態(tài)鏈接是將鏈接過程推遲到了運(yùn)行時(shí)才進(jìn)行。

同樣,假如有程序1,程序2,和Lib.o三個(gè)文件,程序1和程序2在執(zhí)行時(shí)都需要用到Lib.o文件,當(dāng)運(yùn)行程序1時(shí),系統(tǒng)首先加載程序1,當(dāng)發(fā)現(xiàn)需要Lib.o文件時(shí),也同樣加載到內(nèi)存,再去加載程序2當(dāng)發(fā)現(xiàn)也同樣需要用到Lib.o文件時(shí),則不需要重新加載Lib.o,只需要將程序2和Lib.o文件鏈接起來即可,內(nèi)存中始終只存在一份Lib.o文件。
linux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些
動(dòng)態(tài)庫和動(dòng)態(tài)鏈接的例子依然使用上面的代碼,輸出結(jié)果也相同,唯一需要改變的就是Makefile文件。

/Makefile/
main : main.c libadd.so
	gcc main.c -L . -ladd -o main

libadd.so : 
	gcc -fPIC -shared add.c -o libadd.so
	//-shared表示輸出結(jié)果是共享庫類型的  -fPIC表示使用地址無關(guān)代碼奇數(shù)來生產(chǎn)輸出文件
	
.PHONY:clean
clean:
	rm main libadd.so

  • 當(dāng)我們生成可執(zhí)行文件后,可使用ldd命令查看該可執(zhí)行文件所依靠的動(dòng)態(tài)庫。

linux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些

  • 前面提到windows和Linux下庫文件的后綴不同,更根本的原因在于二者文件格式都不同。可以通過file一個(gè)動(dòng)態(tài)庫查看Linux下動(dòng)態(tài)庫的文件類型其實(shí)是ELF格式。ELF動(dòng)態(tài)鏈接文件被稱為動(dòng)態(tài)共享對(duì)象(DSO,Dynamic Shared Objects),簡稱共享對(duì)象;在windows下,動(dòng)態(tài)鏈接文件被稱為動(dòng)態(tài)鏈接庫(Dynamic Linking Library),也就是.dll文件后綴的全稱。

<3>優(yōu)點(diǎn)

  • ①毋庸置疑的就是節(jié)省內(nèi)存;

  • ②減少物理頁面的換入換出;

  • ③在升級(jí)某個(gè)模塊時(shí),理論上只需要將對(duì)應(yīng)舊的目標(biāo)文件覆蓋掉即可。新版本的目標(biāo)文件會(huì)被自動(dòng)裝載到內(nèi)存中并且鏈接起來;

  • ④程序在運(yùn)行時(shí)可以動(dòng)態(tài)的選擇加載各種程序模塊,實(shí)現(xiàn)程序的擴(kuò)展。

四、靜態(tài)庫和動(dòng)態(tài)庫的區(qū)別

1. 靜態(tài)庫

這類庫的名字一般是 libxxx.a ;利用靜態(tài)函數(shù)庫編譯成的文件比較大,因?yàn)檎麄€(gè) 函數(shù)庫的所有數(shù)據(jù)都會(huì)被整合進(jìn)目標(biāo)代碼中,他的優(yōu)點(diǎn)就顯而易見了,即編譯后的執(zhí)行程序不需要外部的函數(shù)庫支持,因?yàn)樗惺褂玫暮瘮?shù)都已經(jīng)被編譯進(jìn)去了。當(dāng)然這也會(huì)成為他的缺點(diǎn),因?yàn)?如果靜態(tài)函數(shù)庫改變了,那么你的程序必須重新編譯 。

2. 動(dòng)態(tài)庫

這類庫的名字一般是 libxxx.so ;相對(duì)于靜態(tài)函數(shù)庫,動(dòng)態(tài)函數(shù)庫在編譯的時(shí)候并沒有被編譯進(jìn)目標(biāo)代碼中,你的程序執(zhí)行到相關(guān)函數(shù)時(shí)才調(diào)用該函數(shù)庫里的相應(yīng)函數(shù),因此動(dòng)態(tài)函數(shù)庫所產(chǎn)生的可執(zhí)行文件比較小。由于函數(shù)庫沒有被整合進(jìn)你的程序,而是程序運(yùn)行時(shí)動(dòng)態(tài)的申請(qǐng)并調(diào)用,所以程序的運(yùn)行環(huán)境中必須提供相應(yīng)的庫。 動(dòng)態(tài)函數(shù)庫的改變并不影響你的程序,所以動(dòng)態(tài)函數(shù)庫的升級(jí)比較方便。

感謝各位的閱讀,以上就是“l(fā)inux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)linux下靜態(tài)鏈接庫和動(dòng)態(tài)鏈接庫的區(qū)別有哪些這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI