靜態庫的制作和使用

? ? ? ? Linux下的靜態庫為lib*.a格式的二進制文件(目標文件),對應于Windows下的.lib格式的文件。

1)命名規則

? ? ? ? lib+庫名字+ .a?? libMytest.a ,則庫名字為mytest。下面以具體的代碼為例介紹如何制作靜態庫。

//main.c
#include <stdio.h>
#include "head.h" 
int main(void)
{int sum = add(2, 24);printf("sum = %d\n", sum);return 0;
}//head.h
#ifndef __HEAD_H_
#define __HEAD_H_
int add(int , int);      
int sub(int , int);
int mul(int , int);
int div(int , int);
#endif//add.c
int add(int a, int b)
{int result = a + b;return result;
}//div.c
int div(int a, int b)
{int result = a / b;return result;
}//mul.c
int mul(int a, int b)
{int result = a * b;return result;
}//sub.c
int sub(int a, int b)
{int result = a - b;return result;
}

? ? ? ? 以上有5段代碼:main.c、head.h、add.c、div.c、mul.c和sub.c。要求將add.c、div.c、mul.c和sub.c制作成庫文件提供給客服使用,這4個文件都是關于頭文件head.h中函數的詳細實現,因此為了不想讓客服知道函數實現的細節和方法,不能將源碼提供給客服,而是以庫文件(二進制文件)的形式提供給客服使用即可。至于如何使用,庫文件已經將函數接口留在了頭文件head.h中,即4個函數聲明。用戶看了頭文件就知道如何使用庫文件了,即如何使用函數。因此最后只需要將main.c、head.h和庫文件給客服即可。(因此,一般庫文件與相對應的頭文件是同一個人來完成的)

? ? ? ? 先強調一下gcc的一個使用。-c參數是用來生成目標文件.o的,但是不鏈接。如: gcc -c zsx.s -o zsx.o? ? gcc -c zsx.c -o zsx.o? ? 對于上面4個.c文件,若工作目錄中只有這4個.c文件,可以用*.c表示這四個文件:? gcc -c *.c? ? 則會生成4個.o文件:add.o? div.o? mul.o和sub.o(在不指出輸出文件名字時,默認是將.c文件的.c改為.o)?。?? gcc -c *.c? ?等價于對每一個單獨的.c文件進行預處理、編譯、匯編后生成各自的 .o文件(檔案庫文件)。同理,對于gcc a.c b.c c.c d.c 最后生成一個a.out文件,其先對每一個源文件生成目標文件,然后將這些目標文件與需要的靜態庫文件鏈接形成可執行文件,至于需要的動態庫文件則是在程序運行時才會加載進去。? ? ??

2)制作靜態庫

? ? ? ? 1)生成對應的.o文件? 2)將生成的.o文件打包。 ar rcs + 靜態庫的名字(libmytest.a)+ 生成的所有的.o??

? ? ? ??一個頭文件(head.h,/mnt/hgfs/share/gcc/Calc/include)和四個.c文件(add.c、div.c、mul.c、sub.c, /mnt/hgfs/share/gcc/Calc/src):? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[root@localhost src]# gcc -c *.c
[root@localhost src]# ls
add.c ?add.o ?div.c ?div.o ?mul.c ?mul.o ?sub.c ?sub.o
[root@localhost src]# ar rcs libMytest.a *.o
[root@localhost src]# ls
add.c ?add.o ?div.c ?div.o ?libMytest.a ?mul.c ?mul.o ?sub.c ?sub.o
此時已經生成了靜態庫文件libMytest.a,該庫文件包含了4個庫函數add.o、div.o 、mul.o和sub.o。ar 工具不包含在gcc中,r --> 將文件插入靜態庫中;c --> 創建靜態庫,不管庫是否存在(存在就不創建);s --> 寫入一個目標文件索引到庫中,或者更新一個存在的目標文件索引(即方便找到需要的庫函數)。ar類似于命令,rcs是三個參數。

(3)使用靜態庫

? ? ? ? 將生成的libMytest.a庫文件和頭文件head.h發送給客服,客服就可以根據頭文件中的接口情況,來知道庫文件的功能 (具體怎么實現的他也不知道),從而客服就可以使用庫文件來完成自己的工作了(main.c):

[root@localhost Calc]# gcc -pedantic -pipe -Wall main.c -I include/ -L src/ -lMytest -o zsx? ? 也等價于:
[root@localhost Calc]# gcc -pedantic -pipe -Wall main.c -I include/ src/libMytest.a -o zsx
[root@localhost Calc]# ./zsx?
sum = 26
分析main.c可以知道,還另外有一個頭文件stdio.h,其對應的是printf函數的聲明,其庫文件是printf函數實現的庫文件,該庫文件有C提供,它們是標準頭、庫文件,因此不需要指明路徑和名稱,且該庫函數為動態庫函數,當程序在運行過程中需要該庫函數時,才會根據頭文件找到相應的庫函數并加載進入內存空間。而,libMytest.a不一樣,為靜態庫文件,因此在載入內存之前就已經鏈接在了一起成為程序代碼的一部分。注意:main函數只是用了add函數,因此在鏈接時只是鏈接了add.o庫函數,并非鏈接了整個庫文件,只需要鏈接使用到的庫函數即可。 例如,一個庫文件libZsx.a包含了qw.o(其有a( )和b( )兩個函數的實現)、qe.o(其有c( )和d( )兩個函數的實現)和qr.o(其有e( )和f( )兩個函數的實現)。當mani函數只是用到a( )和d( )兩個函數時,則最終在鏈接生成可執行程序時,只是會鏈接qw.o和qe.o兩個庫函數,即main函數和這兩個庫函數都在代碼區。

? ? ? ? 庫函數與可執行程序只是差最后一步,都具有前面是哪個階段,且各種規定都完全一樣,都是二進制代碼。

? ? ? ? 調試通過之后,加上-O參數,對代碼進行優化,可以減小最后可執行文件的體積。

(3)靜態庫的優缺點

nm命令可以查看靜態庫文件(.a)和最后生成的可執行文件的詳細屬性。nm?ibMytest.a? 可以查看該靜態庫文件有哪些庫函數(.o文件)。? ?nm zsx 顯示的信息中有:

000000000040056c T add

0000000000400530 T main? //main函數在鏈接的時候加進去的啟動代碼

參數T代表add和main在代碼區。即參數T表示在代碼區的內容。

靜態庫優點:1.發布程序的時候不需要提供對應的庫(動態庫需要);2.加載庫的速度快(庫函數就在代碼區)。缺點:庫被打包到代碼中,增加了代碼的體積;2.庫一旦發生了改變,需要對整個程序進行重新編譯。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385438.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385438.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385438.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

IO多路復用之select

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout); 分析&#xff1a; nfds: 監控的文件描述符集里最大文件描述符加1&#xff0c;因為此參數會告訴內核檢測前多少個文件描述符的狀態 readfds&#xff1a; …

1031. 查驗身份證(15)

一個合法的身份證號碼由17位地區、日期編號和順序編號加1位校驗碼組成。校驗碼的計算規則如下&#xff1a; 首先對前17位數字加權求和&#xff0c;權重分配為&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&#xff0c;8&#xff0c;4&#xff0c;2&#xff0c;1&…

虛擬地址空間

對于每一個進程都會對應一個虛擬地址空間&#xff0c;對于32位的操作系統&#xff08;其指令的位數最大為32位&#xff0c;因此地址碼最多32位&#xff09;&#xff0c;虛擬地址空間的大小為B即0~4GB的虛擬地址空間&#xff0c;其中內核空間為1GB&#xff0c;如下所示&#xff…

Leecode 69. x 的平方根

實現 int sqrt(int x) 函數。 計算并返回 x 的平方根&#xff0c;其中 x 是非負整數。 由于返回類型是整數&#xff0c;結果只保留整數的部分&#xff0c;小數部分將被舍去。 示例 1: 輸入: 4 輸出: 2 示例 2: 輸入: 8 輸出: 2 說明: 8 的平方根是 2.82842..., 由于返回類…

1002. 寫出這個數 (20)

讀入一個自然數n&#xff0c;計算其各位數字之和&#xff0c;用漢語拼音寫出和的每一位數字。 輸入格式&#xff1a;每個測試輸入包含1個測試用例&#xff0c;即給出自然數n的值。這里保證n小于10100。 輸出格式&#xff1a;在一行內輸出n的各位數字之和的每一位&#xff0c;拼…

C/C++中NULL指針

先談一下C/C的強制類型轉換Type cast。與強制類型轉換相對應的是自動類型轉換。或者強制類型轉換叫顯示類型轉換&#xff0c;自動類型轉換叫隱式類型轉換。自動類型轉換會在賦值運算、混合運算、參數傳遞、返回函數返回值、格式化輸出時且當類型出現不一致時發生&#xff0c;轉…

1009. 說反話 (20)

給定一句英語&#xff0c;要求你編寫程序&#xff0c;將句中所有單詞的順序顛倒輸出。 輸入格式&#xff1a;測試輸入包含一個測試用例&#xff0c;在一行內給出總長度不超過80的字符串。字符串由若干單詞和若干空格組成&#xff0c;其中單詞是由英文字母&#xff08;大小寫有區…

動態庫(共享庫)的制作和使用

Linux下的動態庫為lib*.so格式的二進制文件&#xff08;目標文件&#xff09;&#xff0c;對應于Windows下的.dll格式的文件。 &#xff08;1&#xff09;命名規則 lib庫名.so &#xff08;2&#xff09;動態庫的制作 1&#xff09;生成與位置無關的代碼&#xff08;.o&…

孤兒進程、僵尸進進程

一、兒進程與僵尸進程 1、基本概念 我們知道在unix/linux中&#xff0c;正常情況下&#xff0c;子進程是通過父進程創建的&#xff0c;子進程在創建新的進程。子進程的結束和父進程的運行是一個異步過程,即父進程永遠無法預測子進程 到底什么時候結束。 當一個 進程完成它的工…

管道 -pipe

gcc編譯器將源代碼編譯成可執行程序的過程中&#xff0c;需要經過許多中間步驟&#xff08;預處理、編譯、匯編、鏈接&#xff09;&#xff0c;這些過程實際上是由不同的程序來負責完成的&#xff08;/usr/bin/gcc、cpp、ccl、as和ld等&#xff09;。在這個過程的每一個階段中&…

gdb調試器(一)

在默認情況下&#xff0c;gcc在編譯時不會把調試符號插入到最終生成的二進制代碼&#xff08;機器代碼&#xff09;中&#xff0c;因為這樣會急劇增加可執行程序的大小。如果需要在編譯時生成調試符號的信息&#xff0c;則可以采用-g或-ggdb參數。 gcc在產生調試信息時&#x…

1048. 數字加密(20)

本題要求實現一種數字加密方法。首先固定一個加密用正整數A&#xff0c;對任一正整數B&#xff0c;將其每1位數字與A的對應位置上的數字進行以下運算&#xff1a;對奇數位&#xff0c;對應位的數字相加后對13取余——這里用J代表10、Q代表11、K代表12&#xff1b;對偶數位&…

網絡編程套接字API

uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);int inet_pton(int family, const char *strptr, void *addrptr); 分析&#xff1a; 第一個參數可以是AF_INET或AF_INET6&am…

gdb調試器(二)

Linux下的gdb&#xff08;GNU Debugger&#xff09;是一個用來調試C、C程序的調試器&#xff08;命令行方式的調試器&#xff09;&#xff0c;能夠在程序運行期間觀察程序的內部結構和內存的使用情況。程序員也可以使用gdb來跟蹤程序中的錯誤&#xff0c;從而減少程序員的工作量…

gdb調試器(三)

File/file 裝入想要調試的可執行文件 run(r) 執行當前被調試的程序 kill(k) 終止正在調試的程序 quit(q) 退出gdb shell 使用戶不離開gdb就可以執行Linux的shell命令 backtrace(bt) 回溯跟蹤&#xff08;當對代碼進行調試時&#xff0c;run后…

IO多路復用之poll

1. poll函數原型&#xff1a; int poll(struct pollfd *fds, nfds_t nfds, int timeout);參數&#xff1a; fds&#xff1a;指向一個結構體數組的第0個元素的指針&#xff0c;每個數組元素都是一個struct pollfd結構&#xff0c;用于指定測試某個給定的fd的條件 nfds&#x…

makefile文件的書寫規則(make和makefile)

對于makefile&#xff0c;掌握一個規則&#xff0c;兩個變量和三個函數。下面介紹一個規則。 makefile的作用&#xff1a;一個項目代碼的管理工具。當一個項目的代碼文件數&#xff08;如.c文件&#xff09;太多&#xff0c;用gcc編譯會太麻煩&#xff0c;如果全部文件一次性編…

100. 相同的樹

給定兩個二叉樹&#xff0c;編寫一個函數來檢驗它們是否相同。 如果兩個樹在結構上相同&#xff0c;并且節點具有相同的值&#xff0c;則認為它們是相同的。 示例 1: 輸入: 1 1 / \ / \ 2 3 2 3 [1,2,3], [1,2,3] 輸出: true…

makefile的兩個變量(自動變量和普通變量)

(1)普通變量 如&#xff1a; objmain.o add.o sub.o mul.o div.o //將后面的值賦值給obj&#xff0c;obj就是一個普通變量 targetzsx //將zsx賦值給target makefile中已經定義的一些普通變量&#xff08;通常格式都是大寫&#xff0c;類似環境變量&#xff0c;它們都是普通…

【C++ Priemr | 15】虛函數表剖析(二)

一、多重繼承&#xff08;無虛函數覆蓋&#xff09; 下面&#xff0c;再讓我們來看看多重繼承中的情況&#xff0c;假設有下面這樣一個類的繼承關系。注意&#xff1a;子類并沒有覆蓋父類的函數。 測試代碼&#xff1a; class Base1 { public: virtual void f() { cout <…