Linux编程中链接库的使用

链接库本质上是一段可执行的二进制代码,可以被操作系统载入内存执行。按加载的时机不同,链接库可以分为静态链接库和动态链接库。

静态链接库:编译过程中加载进可执行文件的库(静态库省去了运行时加载的消耗,但会导致可执行文件体积增大)
动态链接库:程序运行过程中,动态加载进内存的库(动态库加载需要资源消耗,但可以显著降低可执行文件体积)

什么情况下使用链接库?
1、大型软件项目中,不同模块可以各自完成,然后封装成链接库供上层模块调用。
2、一些通用的功能,如文件处理、数据库接口、算法等,可以封装成库,从而避免每个模块都维护一份独立的通用代码。
3、项目中有很多小的业务模块,可以把各模块制作成统一接口的动态库,主进程根据实际业务按需加载。

静态库的使用,主要有两点:
    一是在主程序里需有静态库接口函数的声明,一般使用一个头文件;
    二是在编译时加载静态库,如linux gcc编译时可以用形如-lcpplib的选项来加载一个文件名为libcpplib.a或libcpplib.so的库。
    这里说明下命名规范,一般建议静态库的后缀用.a,动态库后缀用.so。
    满足上面两点,静态库里的函数就可以像平常一样直接使用了。

动态库的使用,相对要复杂一些。
    这里抛个问题,既然是动态加载的,主程序怎么知道里面有什么函数,怎么调用呢?
    在linux系统里,可以nm查看链接库的符号表,也即是里面的函数表。Linux程序的动态库调用,也提供了4个加载动态库相关的函数:dlopen、dlsym、dlerror和dlcolose。
    #include <dlfcn.h>/*包含的头文件*/
    /*pathname为动态库文件名;mode是打开方式,如RTLD_NOW表示直接解析出动态库中所有的符号*/
    /*此函数返回一个void指针指向加载的库的句柄*/
    void * dlopen( const char * pathname, int mode);
    /*handle为dlopen返回的句柄,symbol为函数名*/
    /*此函数返回库里指定名称的函数的指针*/
    void*dlsym(void*handle,constchar*symbol);
    /*此函数在加载链接库出错时,返回错误信息*/
    char *dlerror(void);
    /*关闭指定的动态库句柄*/
    int dlclose (void *handle);

下面是演示用的代码:
该段代码实现一个动态库调用接口DllRun,通过向该接口传递业务数据、库名、函数名,可以指定相应的库函数来处理数据。
同时iFlag控制该动态库在使用完后是否立即释放,如果不释放(频繁使用的库不释放可以节省加载的开支),则将库句柄指针压入MAP。
#include <dlfcn.h>

typedef int (*dll_func)(char*);/*动态库的函数声明形式*/
map<const char*, dll_func> mapFunc;/*保存不释放的动态库*/

/*
函数功能:加载动态库并执行相应的业务函数
输入参数:strData - 业务数据,根据实现业务情况选择用什么方式传递业务数据,比如数据多且可以按字段划分,可以用map
          strDllName - 需要加载的库名称
          strFunc - 业务的函数名称
          iFlag - 加载方式:
                0 - 第1次加载后Handle保存到map,之后调用不重新加载
                1 - 每次加载均释放掉,下次重新加载
输出参数:strData - 函数执行后输出数据
返回值:0 - 成功;其他失败
*/
int DllRun(char* strData, const char* strDllName, const char* strFunc, int iFlag)
{
    int iRet=-1;
    dll_func pFunc=NULL;/*业务函数的指针*/
    void* pHandle=NULL;
   
    if(NULL == strFunc)
    {
        iRet = -1;
        goto DllRun_RETURN;
    }
   
    if(!iFlag)
    {
        pHandle = mapFunc[strDllName];
    }
   
    if(NULL == pHandle)
    { /*加载动态库*/
        pHandle = dlopen(strDllName, RTLD_NOW);
        if(NULL == pHandle)
        {
            printf("加载链接库[%s]失败: %s\n", strDllName, dlerror());
            iRet = -2;
            goto DllRun_RETURN;
        }
    }
   
    func = dlsym(pHandle, strFunc);/*获取业务函数指针*/
    if(NULL == func)
    {
        printf("获取动态库[%s]的函数[%s]的指针失败: %s\n", strDllName, strFunc, dlerror());
        iRet = -3;
        goto DllRun_RETURN;
    }
   
    iRet = func(strData);/*业务执行*/
    if(0 != iRet)
    {
        goto DllRun_RETURN;
    }

DllRun_RETURN:
    if(iFlag)
    {
        if(NULL != pHandle)
        {
            dlclose(pHandle);
        }
    }
    else
    {
        mapFunc[strDllName] = pHandle;
    }
   
    return iRet;
}

原文地址:https://www.cnblogs.com/JoZSM/p/9858528.html

时间: 2024-11-05 19:28:40

Linux编程中链接库的使用的相关文章

linux下静态链接库的用法

最近在Linux下编程发现一个诡异的现象,就是在链接一个静态库的时候总是报错,类似下面这样的错误: (.text+0x13): undefined reference to `func' 关于undefined reference这样的问题,大家其实经常会遇到.在此,我以详细示例给出常见错误的各种原因以及解决办法,希望对初学者有所帮助. 1.  链接时缺失了相关目标文件(.o) 编译命令: gcc -c test.c gcc -c main.c 得到两个.o文件,一个是main.o,一个是tes

Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf 动态库的后缀为*.so 静态库的后缀为 libxxx.a ldconfig 目录名

Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf  动态库的后缀为*.so  静态库的后缀为 libxxx.a   ldconfig   目录名 转载自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在这之前,我们需要了解一下源代码到可执行程序之间到底发生了什么神奇而美妙的事情. 在Linux操作系统中,普遍使用ELF格

Linux下 静态链接库 和 动态链接库

先来说说C/C++编译过程 编译: 检查语句符号定义,将C/C++代码翻译生成中间语言. 链接: 将中间代码整合,生成可执行的二进制代码. 简单的说,库文件都是一种特殊的中间语言文件,静态库还是一种特殊格式的归档文件(打包的文件). 使用静态库: 1. 先编写库函数 1 #ifndef _PRINT_TEST_H_ 2 3 #define _PRINT_TEST_H_ 4 #ifdef __cplusplus 5 extern "C" 6 { 7 #endif 8 9 extern i

每天进步一点点——Linux编程中的文件锁之flock

转载请说明出处:http://blog.csdn.net/cywosp/article/details/30083015 1. 场景概述 在多线程开发中,互斥锁可以用于对临界资源的保护,防止数据的不一致,这是最为普遍的使用方法.那在多进程中如何处理文件之间的同步呢?我们看看下面的图: 图中所示的是两个进程在无同步的情况下同时更新同一个文件的过程,其主要的操作是: 1. 从文件中读取序号. 2. 使用这个序号完成应用程序定义的任务. 3. 递增这个序号并将其写回文件中. 从图中可得知两个进程读取分

linux编程中接收主函数返回值以及错误码提示

程序A创建子进程,并调用进程B,根据不调用的不同情况,最后显示结果不同. #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <errno.h> int main() { pid_t pid, rpid; int stat; if ((pid = fork()) < 0) { perror("for

Linux系统中“动态库”和“静态库”那点事儿【转】

转自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在这之前,我们需要了解一下源代码到可执行程序之间到底发生了什么神奇而美妙的事情. 在Linux操作系统中,普遍使用ELF格式作为可执行程序或者程序生成过程中的中间格式.ELF(Executable and Linking Format,可执行连接格式)是UNIX系统实验室(USL)作为应用程序二进制

Linux系统中“动态库”和“静态库”那点事儿

摘自http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在这之前,我们需要了解一下源代码到可执行程序之间到底发生了什么神奇而美妙的事情. 在Linux操作系统中,普遍使用ELF格式作为可执行程序或者程序生成过程中的中间格式.ELF(Executable and Linking Format,可执行连接格式)是UNIX系统实验室(USL)作为应用程序二进制接

Linux编程中的坑——C++中exit和return的区别

今天遇到一个坑,折腾了一天才把这个坑填上,情况是这样的: 写了段代码,在main()函数中创建一个分离线程,结果这个线程什么都没干就直接挂掉了,代码长这样: [cpp] view plain copy int main() { 创建一个分离线程(): return 0: } 后来百度)了一下,原来在main()函数中写return,会被编译器优化成,也会像exit一样直接杀死所有进程,所以分离出来的线程什么都没干,就随着进程一起挂掉了. 所以多线程编程中,main()函数想退出线程应当使用 [c

linux编程中printf显示不加换行的缓冲问题

最近在编写linux网络编程时,总是遇到这样的事,程序逻辑没错误,但是程序运行到某个地方就停在那里了,后来才发现在prinrf()中加入换行能正常运行了,如“ printf("123"); ”改成“ printf("123\n"); ”就好了 慢慢的找到了一篇博文可以解释这个问题:博文链接:http://blog.csdn.net/ferlansue/article/details/7925522 解释如下: printf会把东西送到缓冲区,而如果缓冲区不刷新到话,