Fork me on GitHub

Linux下创建和使用C语言函数库

函数库介绍

函数库分为:

  • 静态库
  • 共享库(动态加载库)

应用程序在链接静态库时候,将使用的静态库对象嵌入至可执行映像文件中;而在链接共享库时,仅在可执行映像文件中保留加载目标对象所需的信息,在调用时,才真正将目标对象加载至内存。 静态库特点:

  1. 运行时无需外部库的支持,可执行文件中已经嵌入了所需的静态库目标对象,所以可执行文件可以脱离静态库独立运行。
  2. 较高的运行速度,运行时不需要加载其他目标对象
  3. 可执行文件体积较大
  4. 不容易维护,每次修改静态库,必须重新链接

共享库特点:

  1. 可执行文件体积较小
  2. 容易维护,共享库中对象发生变化,应用程序不需要重新编译
  3. 可执行文件中不包含共享库中调用的目标对象,因此不能离开动态库独立运行
  4. 运行速度比较慢,因为程序启动时需要加载共享库

静态库

静态库创建

静态库命名规则是lib开头,.a作为文件名后缀。可以使用ar命令作为静态库管理工具。ar可以将多个.o文件打包在一起,构成一个静态库文件。

案例:

先准备两个C源文件如下:

//exam1.c
int add(int x, int y)
{
    return x + y;
}
//exam2.c
int func(int count)
{
    int sum=0;
    int j;
    for(j=0; j<=count; j++)
    {
        sum=sum+j;
    }
    return sum;
} 

编译两个源文件,后使用ar创建静态库:

gcc -c -Wall exam1.c
gcc -c -Wall exam2.c
ar -crq libdemo.a exam1.o exam2.o

这样,我们就创建了一个简单的静态库。

静态库使用

定义静态库应用接口

//exam.h
extern int add(int x,int y);
extern int func(int count);

使用静态库

//testexam.c
#include <stdio.h>
#include "exam.h"

int main(void)
{
    int val;
    int x,y;
    x=12;
    y=18;
    val=add(x,y);
    printf("the mult of x adn y is %d\n",val);
    val=func(100);
    printf("the sum is %d \n",val);
    return 0;
}

编译运行

gcc -o testexam  testexam.c -L ./ -ldemo 

解释: -L指定了静态库所在的目录, ./就是当前目录

-ldemo指定了静态库的名称libdemo.a

共享库

若在同一目录下存在同名的共享库和静态库,gcc会优先使用共享库,除非指定了-static.

创建共享库

gcc -fPIC -c exam1.c
gcc -fPIC -c exam2.c
gcc -shared -o libdemo.so exam1.o exam2.o

以上三句指令将exam1.c和exam2.c编译成了libdemo.so共享库文件。 -fPIC告诉gcc创建地址独立的目标文件 -shared告诉gcc创建一个共享库文件

共享库使用

链接着共享库的应用启动时,一个程序装载器将自动运行,该程序装载器为/lib64/ld-linux.so.X,,它的作用是查找并装载应用程序所依赖的所有共享库的中的目标对象。

将共享库libdemo.so放在/usr/local/lib/目录下 链接共享库

gcc -o testexam testexam.c /usr/local/lib/libdemo.so  

查看程序使用共享库情况

ldd testexam

动态链接库

动态链接库是使用共享库的一种方式,在运行的任何时刻可以动态加载共享库。和一般共享库不同,通常应用程序启动时,不立即加载共享库,而是在需要时,动态加载共享库。 以动态链接的方式使用共享库分为三个步骤:

  1. 打开共享库文件
  2. 接着取得要调用函数的地址,根据地址使用函数指针进行调用
  3. 关闭共享库

Linux环境提供了一组API函数可以动态链接共享库,头文件定义在/usr/include/dlfcn.h中。

案例

//exam.c
#include <stdio.h>
#include <dlfcn.h>
#include "exam.h"
#include <stdlib.h>

int main(void)
{
    int val;
    int (*add_d)(int,int);
    int (*func_d)(int);
    void *handle;
    char *err;
    int x,y;
    x = 12;
    y = 18;
    handle = dlopen("/usr/local/lib/libdemo.so",RTLD_LAZY);
    if (handle == (void *)0)
    {
        fputs(dlerror(),stderr);
        exit(-1);
    }
    add_d = dlsym(handle,"add");
        err = dlerror();
        if (err != NULL)
        {
            fputs(err,stderr);
            exit(-1);
        }

    func_d = dlsym(handle,"func");
        err = dlerror();
        if(err != NULL)
        {
            fputs(err,stderr);
            exit(-1);
        }
    val = (*add_d)(x,y);
    printf("the mult of x and y is %d\n",val);
    val = (*func_d)(100);
    printf("the sum of 1 to 100 is %d\n",val);
    dlclose(handle);
    return 0;
}

编译链接

gcc -rdynamic exam.c -o exam -ldl

执行

niuhe@niuhe-ubuntu:/tmp/exp$ ./exam 
the mult of x and y is 30
the sum of 1 to 100 is 5050

GUN C函数库——glibc

glibc是GNU开发的一套标准C语言标准函数库的实现。通常linux发行版都默认安装好了,查看glic的版本号ldd --version.

Comments