-因本人才疏学浅,错误之处望大家指正批评
本文资料来源
首先我们要知道什么是库
库是什么?
库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都是从零开始,因此库的存在意义非同寻常
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.库有两种,一种是静态库,一种是动态库.Linux下的名称和Window下的名称不同.
库中可以理解为一堆封装好的函数.
库的编号
编号的约定:
library_name.major_num.minor_num.patch_num
如libgdbm.so.2.0.0
? 库名+库的类型:ligdbm.so
? 主版本:2
? 次版本号:0
? 补丁号:0
在说静态库和动态库之前我们先讲一下一个C语言从诞生到执行的全过程吧
Linux下的C语言要经过
预处理--编译--汇编--链接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ow6iRXU2-1587793310586)(http://besthpy.top/blog/20190519/SXmuEK7nvyEk.png?imageslim)]
静态库和动态库的作用
静态库、动态库区别来自[链接阶段]如何处理库、链接成可执行行程库.分别称为静态链接方式、动态链接方式.
四个步骤,并最终生成可执行文件,这个可执行文件默认保存为a.out
静态库(static library)
在Linux下静态库的名称为 (.a )
在Window下静态库的名称为(.lib)
静态库编写例程——liberr.h,liberr.c,errtest.c
? liberr.h:静态库头文件
? liberr.c:出错处理库实现
? errtest.c:用来测试库的程序
编写静态库
请看下文的ar命令
共享库(动态链接库)
在Linux下动态库的名称为 (.so )
在Window下动态库的名称为(.dll)
编写一个共享库
举一个例子
func1.c
void str(char *str){
printf("%s\n",str);
}
func2.c
void data(int a){
printf("%d\n",a);
}
然后用
gcc -c func1.c func2.c
生成.o文件
Linux下的.o文件就相当于Window下的.obj文件
他们都是对象文件
然后再用
gcc -shared -fpic -o func.so func1.o func2.o
生成一个func.so的共享库文件
编译目标文件时使用gcc的-fPIC选项,产生位置无关代码,以便加载到任何地址
-shared 生成共享目标文件。通常用在建立共享库时
然后用
ls
查看时,就会发现多了一个func.so的动态库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kEvczDpa-1587793310590)(http://besthpy.top/blog/20190527/nXJ74BEwR5sq.JPG)]
动态库的静态调用
main.c
#include<stdio.h>
extern void str(char *str1); //引用别的文件里面的函数必须要的声明
extern void data(int);
int main(void){
str("hello");
data(123456);
}
引用方式
注意一定要加 ./
gcc main.c ./func.so
./a.out
结果如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LTsmrgjB-1587793310593)(http://besthpy.top/blog/20190527/9Lj2LGu5VXiX.JPG)]
动态库的动态加载
动态库的静态加载一般需要以下的几个函数
必须的头文件<dlfcn.h>
几个常用的函数
dlopen
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
filename:要加载的共享文件名;NULL打开当前执
行文件
flag:RTLD_LAZY,加载对象的符号在被调用时解
析;RTLD_NOW,立即解析所有符号;RTLD_GLOBAL,与前两个任何一个 “或”导出所有符号
成功返回指针;失败返回NULL;
dlsym
#include <dlfcn.h>
void *dlsym(void *handle, char *symbol);
handle:dlopen返回的句柄指针
symbol:包含符号名称的字符串
成功返回指向符号的指针;失败返回NULL;
dlerror
#include <dlfcn.h>
const char *dlerror(void);
返回描述错误的字符串;否则返回NULL;
下面是一个动态加载的例子
在上面的基础上
dl.c
#include<dlfcn.h>
#include<stdio.h>
main(){
void *handle=dlopen("./func.so",RTLD_NOW); //返回的是一个指向动态
//库的指针
//创建了两个分别只想对应的函数的指针
void (*test1)(char *) =dlsym(handle,"str");
void (*test2)(int )=dlsym(handle,"data");
//调用这两个指针
(*test1)("hello!");
test2(123456);
//最后关闭这个指向动态库的指针
dlclose(handle);
}
使用的命令
gcc dl.c -ldl
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6GQts1d5-1587793310596)(http://besthpy.top/blog/20190527/splOUcWmkdam.JPG)]
命令工具
nm命令
列出编入目标文件或二进制文件的所有符号
查看程序调用什么函数
查看一个给定的库或者目标文件是否提供了所需函数
语法:nm [options] file
常用的选项
选项 | 作用 |
---|---|
-c | 将符号名转换为用户级的名字 |
-s | 当用于存档(.a)文件时,输出把符号名映射到定义该符号的模块或成员名的索引 |
-u | 只显示未定义的符号——在被检查的文件外部定义的符号 |
-l | 使用调试信息输出定义每个符号的行号,或者未定义符号的重定位项 |
一个例子
test.c
#include<stdio.h>
#include"test.h"
void print(){
printf("rainy days\n");
}
main.c
#include"test.h"
int main(){
print();
return 0;
}
test.h
void print();
然后再用nm命令查看一下
一开始我们没有链接的时候
是什么都没有的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AHWzzXGW-1587793310597)(http://besthpy.top/blog/20190522/aPih8FUwHVJ4.png?imageslim)]
然后我们把这三个文件连接起来
gcc -c test.c main.c
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cvmOLCqj-1587793310599)(http://besthpy.top/blog/20190522/HHRDk6RKNjgg.png?imageslim)]
ar命令(静态库)
创建高度结构化的存档文件,通常用来创建静态库
语法: ar [-]{dmpqrtx} [member] archive
选项 | 描述 |
---|---|
-c | 存档文件不存在则创建而不发出警告 |
-s | 常见或升级从符号到定义他们的成员之间的交叉索引映射表 |
-r | 向存档文件插入files,替换已有的任何同名成员。新成员添加到存档文件的末尾 |
-q | 把files添加到存档文件的末尾而不检查是否进行替换 |
ar 最常见的就是建立一个静态库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uZKxPgIA-1587793310600)(http://besthpy.top/blog/20190522/yg8AJPge1B5i.png?imageslim)]
然后下面举一个使用的例子
test_program.c(用来使用这个静态库)
#include<stdio.h>
extern void print(); //必须的头文件,使用别的文件的函数时,必须要的语句
int main(){
print();
}
gcc test_program.c 1.a(固定的格式)
gcc 目标程序 使用的静态库
代码截图如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kzzK6sOH-1587793310602)(http://besthpy.top/blog/20190522/XAVLSUjnjRX1.png?imageslim)]
资料引用
声明 本文资料来源于网络,以上图文,贵在分享,版权归原作者以及原出处一切,内容为作者观念,并不代表本人附和其观念和对齐真实性负责,如伤害到您的利益,请您在评论下方留言