1.共享库的概念和使用
1.1 共享库的概念和特性
(1)基本概念
共享库的本质是有若干个目标文件.O打包生成的.so文件链接共享库的本质就是将被调用的代码指令在共享库中的相对地址嵌入到调用模块中,具体体现在最终的可执行文件
(2)基本特性
- a. 共享库占用空间小,即使修改里库中的代码,只要接口(相对地址)保持不变,则不需要重新链接
- b.使用共享库的代码时,需要以来于具体的库文件中,执行效率相对静态库来说略低
- c.目前主流的商业开发中都使用共享库方式
1.2 共享库的生成和调用步骤
(1)生成步骤
- 1.编写源代码文件xxx.c, 如:vi add .c
- 2.只编译不链接生成目标文件 xxx.o 如:cc -c -fpic/生成位置无关码,也就是相对路径/ add.c
- 3.生成共享库文件,具体指令如下:
cc -shared 目标文件 -o lib库名.so
如:cc -shared add.o -o libadd.so
(2)调用步骤
- a.编写测试源代码文件xxx.c, 如: vi main.c
- b.只编写不链接生成目标文件xxx.o, 如:cc -c main.c
- c.链接共享库文件,链接的方式有以下三种:
1)直接链接
cc main.o libadd.so
2) 使用编译选项进行链接
cc main.o -l 库名 -L 库文件所在的俄路径
如:cc main.o -l add -L .
3)配置环境变量LIBRARY_PATH
export LIBRARY_PATH=$LIBRARY_PATH:.
cc main.o -l add
注意:
- 当共享库执行找不到时执行如下指令
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:路径
注意:
- gcc编译器缺省链接共享库,可以通过-static选项强制链接静态库
- 使用ldd a.out 可以查看 a.out所依赖的共享库
例子(add_shared, circle_shared)
1.3 共享库的动态加载
#include <dlfcn.h>
Link with -ldl.
(1)dlopen 函数
void *dlopen(const char *filename, int flags);
第一个参数:字符串形式的文件名
第二个参数:具体的操作标志
RTLD_LAZY - 表示延迟加载
RTLD_NOW - 表示立即加载
返回值:成功返回该文件对应的句柄(标识),失败返回NULL;
函数功能:
主要用于打开/加载第一个参数指定的共享库文件;
(2)dlsym函数
void *dlsym(void *handle, const char *symbol);
第一个函数:void* 的句柄信息,dlopen函数的返回值;
第二个参数:字符串形式的符号名,这里指函数名
返回值:成功则返回符号名(函数名)对应的内存地址,失败返回NULL;
函数功能:
主要用于查找指定共享库中指定函数在内存空间的地址;
(3)dlclose函数
int dlclose(void *handle);
函数功能:
主要用于关闭/卸载参数指定的共享库文件,参数一般传递dlopen函数的返回值;
成功返回0,失败返回非0;
(4)dlerror函数
char *dlerror(void);
函数功能:
主要用于在调用dlopen()/dlclose()/dlsym()之后进行错误原因的获取,如果没有产生错误,则返回NULL。
如果产生错误,则返回对应的错误信息;
例子:(05dynamic.c)
2.C语言中的错误处理
如:
int main()
{
if(...){
return -1;//表示程序出错结束
}
return 0;//表示程序正常结束
}
2.1 C语言中的错误表现形式(错了吗?)
- 一般来说,C语言中的函数都是通过返回值来表达是否出错的,而具体的表现规则如下:
- (1)对于返回值类型为int的函数来说,如果函数的计算结果不可能是负数时,一般使用返回-1表示出错,返回其他数据
则表示正常;
(2)对于返回值类型为int的函数来说,如果函数的计算结果可能是负数时,一般使用指针作为函数的行参用于将函数的
计算结果带出去,而函数的返回值专门用于表示是否出错,一般使用返回-1表示出错,返回0表示正常结束;
(3)对于返回值类型为指针类型的函数来说,一般使用返回NULL来表示调用失败/出错;
(4)对于不考虑是否失败的函数来说,返回值类型直接使用void即可;
2.2 错误编号(为什么错了?)
error本质上就是一个int类型的全局变量当系统/库函数调用失败时,会自动设置error的数值来表达错误的原因;
#include<errno.h>包含里对errno变量的外部声明以及各种错误的编号定义等;
/etc/passwd - 用于存放当前系统的帐号管理信息等;
/etc/shadow - 用于存放当前系统的账户密码信息等;
练习:
vi 07errno.c文件首先打印errno的数值,使用fopen函数打开万文件/etc/passwdd文件,判断是否打开失败,若失败则再次打印errno的数值;