庫 是一種代碼的二進制的封裝形式,將.o檔案打包封裝就成了庫,庫可以在任何地方使用,但用戶卻不能看見他的具體實作,庫有利于代碼模塊化,只要介面設計得合理,改變庫的內部實作,不會影響到用戶級別的代碼使用,
動態庫
1.封裝動態庫
假設有源代碼sum.c, sub.c
gcc sum.c -c -o sum.o
gcc sub.c -c -o sub.o
//封裝成庫
gcc -shared -fPIC -o libmymath.so sum.o sub.o
/*
-shared 表示要編譯一個共享庫
-fPIC 表示要生成與位置無關的代碼
-o 要創建的庫的名稱,一般約定庫的名稱格式如下:
lib庫名.so
*/
2.動態庫的編譯
只需把.h與.so檔案提供給用戶使用即可
用戶編譯形式如下:
gcc main.c -I 頭檔案路徑 -L 庫檔案路徑 -l庫名
ex:
gcc test.c -I ../mymath/ -L ../mymath/ -lmymath
//路徑可以是相對路徑也可以是絕對路徑
3.依賴動態庫的程式執行
用戶執行時需要指明庫所在的路徑,通常通過添加環境變數的方式實作
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:庫檔案路徑
查看庫環境變數
echo $LD_LIBRARY_PATH
使用命令lld可查看
靜態庫
1.封裝靜態庫
假設有源代碼sum.c, sub.c
gcc sum.c -c -o sum.o
gcc sub.c -c -o sub.o
//靜態庫的后綴名是.a
ar -rc libmymath.a sum.o sub.o
//-rc 中的r 表示插入目標檔案到靜態庫中,c表示創建指定的靜態庫
2.靜態庫編譯
gcc main.c -I 頭檔案路徑 -L 庫檔案路徑 -l庫名
ex:
gcc test.c -I ../mymath/ -L ../mymath/ -lmymath
//如果該路徑下有動態庫,則會優先使用動態庫
//如果要靜態鏈接自己或第三方的庫,但又要動態鏈接系統的庫,那么編譯方式如下
gcc xxx.c -I 頭檔案路徑 靜態庫的完整的名稱
ex:
gcc xxx.c -I ../mymath/ ../mymath/libmymath.a
//全部使用靜態庫,在編譯時加 -static
gcc main.c -I 頭檔案路徑 -L 庫檔案路徑 -l庫名 -static
動態庫與靜態庫的主要區別
靜態庫和動態庫都是二進制檔案(目標檔案)的封裝
對于動態庫,編譯程式時,并沒有把動態庫的內容復制到可執行檔案中去,僅僅是做了一個標記,表示可執行檔案需要用到某個動態庫,當執行程式時,首先需要去LD_LIBRARY_PATH指定的路徑下(或庫的標準路徑,如/lib,如/usr/lib等)查找需要的動態庫,才能正常運行,
對于靜態庫,編譯程式時,會把靜態庫中的內容復制到可執行檔案中去,運行程式時,就不再需要那個靜態庫了,
我們使用得最多的是動態庫,理由:
1、程式運行時,動態庫在記憶體中只需要一份,而靜態庫,則可能會有多份拷貝,造成所謂的代碼
冗余,
2、當庫更新升級時,對于動態庫來說只要介面不變,則不需要重新編譯用戶程式,如果是靜態庫,則庫改變了,所有使用該庫的程式都必須重新編譯,
C&C++混合編程中庫的處理
c++兼容c,能夠直接使用這些功能,用c開發的功能如果打包成庫了(經c編譯器編譯成目標檔案),目標檔案中的函式名就已經確定下來,而c++編譯器會對函式名進行處理,會由于函式名字不匹配而導致呼叫c庫中的函式失敗
解決辦法:
C++提供了一個關鍵字: extern "C", 稱為鏈接指示,通常寫在頭檔案中,但c編譯器并不認識這個關鍵字,因此用法如下:
#ifdef __cplusplus
extern "C"
{
#endif
int sum(int a, int b); // C函式宣告
int sub(int a, int b); // 可包含多個函式宣告
#ifdef __cplusplus
}
#endif
負責任的程式員,理應在c語言撰寫的庫中加入該關鍵字
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/487412.html
標籤:C
