静态库的制作和使用

        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.mzph.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 <…