静态链接库和动态链接库的区别

静态链接库和动态链接库的区别

一、静态链接库

预编译->编译->汇编->链接

Linux:

生成目标文件

g++ -c source.cpp -o source.o

打包成静态链接库

ar -crv source.a source.o

使用静态链接库

g++ test.cpp -L静态链接库目录 -l静态链接库名称没有后缀

 

二、动态链接库

使用动态链接库是为了规避静态链接库的两个问题。

一个是多个副本的问题,对于静态库都是在编译时刻将其编译到源代码当中,在运行时刻不会再和静态库有任何关系。这样的好处是快,但是造成了空间的浪费

另一个是发布的一致性问题和更新问题,如果是静态库,如果对静态库进行了更新,那么需要重新编译代码,并且提示用户进行下载整个软件,这样会造成很多不变,浪费大量带宽。如果是动态库,只需要更新相应的动态链接库即可,整个软件不需要修改。

Linux平台:

生成目标文件

g++ -fPIC source.cpp -o source.o

动态链接库

g++ -shared source.so source.o

或者合并为一个命令

g++ -fPIC -shared source.so source.cpp

关于在使用中定位动态链接库的位置,需要注意一些问题,默认动态链接库是在/lib 或者 /usr/lib之下的

如果要在其他文件夹之下,需要修改 /etc/ld.so.cache文件


动态链接库的使用

动态链接库与普通的程序相比而言,没有main函数,是一系列函数的实现。通过shared和fPIC编译参数生产so动态链接库文件。程序在调用库函数时,只需要连接上这个库即可。例如下面实现一个简单的整数四则运输的动态链接库,定义的caculate.h和caculate.c两个文件,生产libcac.so动态链接库。

程序代码如下:

复制代码
/*caculate.h*/

#ifndef CACULATE_HEAD_
#define CACULATE_HEAD_
//加法
int add(int a, int b);
//减法
int sub(int a, int b);
//除法
int div(int a, int b);
//乘法
int mul(int a, int b);

#endif
复制代码
复制代码

/*caculate.c文件*/
#include "caculate.h" //求两个数的和 int add(int a, int b) { return (a + b); } //减法 int sub(int a, int b) { return (a - b); } //除法 int div(int a, int b) { return (int)(a / b); } //乘法 int mul(int a, int b) { return (a * b); }
复制代码

编译生产libcac.so文件如下: gcc -shared -fPIC caculate.c -o libcac.so
编写一个测试程序调用此动态链接库的函数,程序如下所示:

复制代码
#include 
#include "caculate.h"

int main()
{
    int a = 20;
    int b = 10;
    printf("%d + %d = %d\n", a, b, add(a, b));
    printf("%d - %d = %d\n", a, b, sub(a, b));
    printf("%d / %d = %d\n", a, b, div(a, b));
    printf("%d * %d = %d\n", a, b, mul(a, b));
    return 0;
}
复制代码

编译生产可执行文件main如下:gcc main.c -o main -L ./ -lcac   (其中-L指明动态链接库的路径,-l后是链接库的名称,省略lib)
程序执行结果如下所示:

静态链接库和动态链接库的区别_第1张图片

 3、获取动态链接库的函数
  linux提供dlopen、dlsym、dlerror和dlcolose函数获取动态链接库的函数。通过这个四个函数可以实现一个插件程序,方便程序的扩展和维护。函数格式如下所示:

复制代码
#include 

void *dlopen(const char *filename, int flag);

char *dlerror(void);

void *dlsym(void *handle, const char *symbol);

int dlclose(void *handle);

 Link with -ldl.
复制代码

dlopen()是一个强大的库函数。该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。写个测试程序调用上面生产libcac.so库如下所示:

复制代码
#include 
#include 

#define DLL_FILE_NAME "libcac.so"

int main()
{
    void *handle;
    int (*func)(int, int);
    char *error;
    int a = 30;
    int b = 5;

    handle = dlopen(DLL_FILE_NAME, RTLD_NOW);
    if (handle == NULL)
    {
    fprintf(stderr, "Failed to open libaray %s error:%s\n", DLL_FILE_NAME, dlerror());
    return -1;
    }

    func = dlsym(handle, "add");
    printf("%d + %d = %d\n", a, b, func(a, b));

    func = dlsym(handle, "sub");
    printf("%d + %d = %d\n", a, b, func(a, b));

    func = dlsym(handle, "div");
    printf("%d + %d = %d\n", a, b, func(a, b));
    
    func = dlsym(handle, "mul");
    printf("%d + %d = %d\n", a, b, func(a, b));

    dlclose(handle);
    return 0;
}
复制代码

程序执行结果如下所示:gcc call_main.c -o call_main -ldl
静态链接库和动态链接库的区别_第2张图片


你可能感兴趣的:(静态链接库和动态链接库的区别)