9·C语言---静态链接库 与 动态链接库笔记

1· 比较早出现的是 静态链接库。静态库是商业公司将自己的函数库源代码经过只编译不链接形成 .o 文件,然后用ar工具将 .o 文件归档成 .a 文件( .a 文件又叫 静态链接库文件)。商业公司通过发布 .a 文件和 .h 头文件来提供静态库给客户使用,客户得到 .a 和 .h 文件后,通过 .h 头文件得知库函数的原型,然后在自己的 .c 文件中直接调用这些库文件,在链接的时候连接器会去 .a 文件中调出被调用的 那个函数被编译后得到的 .o二进制代码段链接进去形成最终的可执行程序。

2· 动态链接库后出现于静态链接库,相较于静态链接库,动态链接库效率更高一些。现在一般都是使用动态链接库。静态链接库在用户链接自己的可执行程序时,就已经把调用的库中的函数代码段链接进最终可执行程序中,这样的好处是可以执行,坏处是占地方—> 当有多个应用程序都使用了这个库函数时,实际上在多个应用程序最后生成的可执行程序中都各自有一份这个库函数的代码段。当这些应用程序同时在内存中运行时,实际上在内存中有多个这个库函数的代码段,这完全重复了。
而动态链接库本身不将库函数的代码段链接入可执行程序,只是做一个标记。然后当应用程序在内存中执行时,运行时环境发现它调用了一个动态链接库时,会去加载这个动态库到内存中,然后以后不管有多少个应用程序调用这个函数库的函数都会跳转到第一次加载的地方去执行(不会重复加载)。

3· gcc中编译链接程序默认是使用动态链接库,要是需要得到静态链接库就需要显式用 -static 来强制静态链接。

4· 库函数的使用需要注意3点:第一,包含相应的头文件;第二,调用库函数时注意函数原型;第三,有些库函数额外链接时需要用 -lxxx 来指定链接;第四,如果是动态链接库,要注意 -L 指定动态库的地址。

5· 自己制作静态链接库并使用
(1)第一步,首先使用gcc -c 只编译不链接,生成 .o 文件;再使用ar工具进行打包成 .a 归档文件(静态库)。
库名不能乱起,格式是:lib+库名称.a
注意:静态链接库制作出来后,发布时需要将 .a 文件和 .h文件(源文件的头文件)一起打包发布。

库函数里面只有 有用的函数,没有mian函数哦。

Makefile:使用一个makefile脚本 方便编译制作静态链接库,只需要make一下。

all:
	gcc cjj.c -o cjj.o -c 
	 # -o 就是重命名,-c 就是只编译不链接。
	 #所以:把cjj.c 源文件只编译不链接并且重命名为cjj.o文件(好像又叫目标文件)
	ar -rc libcjj.a cjj.o # ar 相当于是一个指令,与gcc一样;-rc 就是制作创造库。
	#所以:把(原料文件)cjj.o 制作一个libcjj.a 归档文件。
	#这里的lib后面的cjj可以不用与源文件cjj.c的名字一致,
	#因为lib后面的名字是静态链接库的名字,可以改一下。

# 关于libcjj.a 文件的一些注意:lib + 静态库的名字.a  

(2)第二步,使用静态链接库。把 .a 和.h文件放在一个文件夹里面,然后在 .c 文件中包含库的 .h文件,然后直接使用库函数。
编译方法:gcc test.c -o test
报错:test.c:(.test + 0xa): undefine reference to ’ .h中的函数1 ’
原因是:函数没有错,编译的时候链接有问题。
解决方法:指定链接.
gcc test.c -o test -lcjj
因为前面制作了一个叫cjj的静态库链接(因为:libcjj.a 所以库名就是 cjj )
又报错:/usr/bin/ ld :cannot find -lcjj
collect2:error: ld returned 1 exit status
原因:没有指定路径,应该指定为当前路径来找。
解决方法:
gcc test.c -o test -lcjj -L. // -L :指定路径 ;// . 表示在当前路径

6· 自己制作动态链接库并使用
6·1 动态链接库的后缀是 .so (对应Windows系统中的dll),静态库的扩展名是.a
6·2 动态链接库的制作:
(1)创建一个动态链接库。
Makefile:

all:
	gcc cjj.c -o cjj.o -c -fPIC
	gcc -o libcjj.so cjj.o -shared

-fPIC : 是位置无关码 ; - shared : 按照共享库的方式链接。
注意:做库的人给用库的人发布库时,发布libxxx.so 和 xxx.h就可以。

(2)第二步,使用共享库。把 .so 和.h文件放在一个文件夹里面,然后在 .c 文件中包含库的 .h文件,然后直接使用库函数。
编译方法:gcc test.c -o test
报错:test.c:(.test + 0xa): undefine reference to ’ .h中的函数1 ’
解决方法:指定链接.
gcc test.c -o test -lcjj

又报错:/usr/bin/ ld :cannot find -lcjj
collect2:error: ld returned 1 exit status
原因:没有指定路径,应该指定为当前路径来找。
解决方法:
gcc test.c -o test -lcjj -L. // -L :指定路径 ;// . 表示在当前路径

编译成功了,但是运行有错误:
error while loading shared libraries:libcjj.so:cannot open shared object file:No such file or directory
原因:动态链接库运行时需要被加载(运行时环境在执行test程序的时候发现它动态链接了libcjj.so,于是回去固定目录尝试加载libcjj.so ,如果加载失败就会打印以上错误信息。)

解决方法1:将libcjj.so 放到固定目录下就可以了,这个固定目录一般是/usr/lib目录。
输入指令:sudo cp libcjj.so /usr/lib
然后 : . / test
可以出现正确结果。

【推荐使用这个方法,不会对/usr/lib 系统目录吓唬乱搞】
解决方法2:使用环境变量 LD_LIBRARY_PATH
操作系统在加载固定目录 /usr/lib 之前会先去LD_LIBRARY_PATH环境变量所指定的目录下去寻找,如果找到就不用去 /usr/lib 下面找了,如果找不到再去这个目录下找。所以,将libcjj.so 所在的目录导出到LD_LIBRARY_PATH环境变量中去即可。

先用指令pwd查出当前libcjj.so文件所在路径。
然后:
export LD_LIBRARY_PATH =$LD_LIBRARY_PATH:( [这里是libcjj.so 文件的路径] )

然后 再 . / test
可以运行。

补充:
ldd命令:可以再一个使用了共享库的程序执行之前**解析出这个程序使用了哪些共享库,**并且查看共享库是否能被找到,能被解析(决定这个程序是否能被之前执行)。

输入指令:ldd test
就会出来test程序用了哪些库。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中的隐式静态链接库(.a)是一个在编译时将库的对象代码与应用程序一起链接起来的库文件。它作为一个整体被插入到可执行文件中,使得应用程序在运行时能够使用其中的函数和变量。 使用隐式静态链接库的主要步骤如下: 1. 首先,需要将库文件(.a文件)放置在合适的路径下,确保编译器能够找到它。 2. 在编写C语言程序时,需要包含对应的库头文件,以便能够使用库中的函数和变量。 3. 在使用库函数或变量时,需要在编译命令中链接对应的库文件。这可以通过在编译命令中使用参数"-l"和"-L"来完成。"-l"用于指定库文件的名称,"-L"用于指定库文件的路径。 4. 编译时,编译器会从指定的库文件中提取需要的函数和变量,并将它们与应用程序的代码合并在一起生成可执行文件。 隐式静态链接库的一个优点是,使用它们可以直接将库的功能嵌入到可执行文件中,无需额外的库文件依赖。这样可以简化程序的部署和分发。 然而,隐式静态链接库的缺点是,当多个应用程序都使用同一个库时,每个可执行文件都会包含库的副本,导致可执行文件的大小增加。而且,如果库的更新需要重新编译所有依赖它的应用程序。 总之,隐式静态链接库是一种在编译时将库的对象代码与应用程序进行链接的方式,使得应用程序能够直接使用库中的函数和变量。它的使用需要在编译命令中显式指定库文件,并将其与应用程序代码合并生成可执行文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值