Linux 函数库设计

来源:互联网 发布:淘宝王者荣耀cdkey 编辑:程序博客网 时间:2024/04/28 14:32

函数库----笔者理解为若干函数的代码集合。其实就是若干个具有特定功能的函数的二进制代码经过打包处理后放在在一个文件中,我们称之为函数库。从代码实现的角度来看,就是若干个函数写在同一个文件中,然后编译该文件成为目标.o文件,接着将该.o文件打包成一个可以被链接的库,最后放到一个编译器可以找到哦的路径中(如/lib/目录)。通常一个函数库里有多个具有特定功能的函数,当用户需要使用到某个函数时,可以包含声明该函数的头文件,然后直接调用该函数。如平常使用到的printf()函数,就是来自libc.so这个函数库,并且printf()这个函数是在 stdio.h中申明的,因此,当我们需要调用该函数时,可以在我们的代码中include这个头文件, 然后直接调用该函数。这是从用户的角度理解的函数库,从库的实现者的角度来看,即当我们需要建立自己的函数库时,我们要做的事情就变得多了起来。在进入函数库的设计阶段之前,还是来详细说明一下库的一些性质。

函数库可以分为静态函数库和动态函数库,在Linux系统中,当进入/lib、/usr/lib 目录时,可以发现很多 类似:libxxx.a、libxxx.so 的文件,实际上.a文件就是静态函数库,.so文件就是动态函数库。这些库都是我们在安装系统或者后来安装软件时自动安装的一些函数库,这些都不是我们讨论的范围,我们要做的是自己从零开始制作一个可以像libc.so一样被直接调用的库。先了解两个概念:静态链接和动态链接

这两个概念都是编译器链接程序的方法,我们知道编译器编译代码的最后一步就是链接,即:将源程序的.o文件和使用到的库文件进行链接,以形成一个可执行文件。这里的链接方法就分静态链接和动态链接。所谓静态链接,就是源程序的.o文件和函数库(.a文件)一起被链接成一个文件,当执行该程序时,整个文件都被调入内存中。而动态链接则是在链接的时候只是将函数库(.so文件)的信息加到源程序的.o文件中,当执行该程序时,真正的函数库由内核调入内存中,和.o文件的内容形成可执行代码。可以作出假设:有A、B、C三个程序,每个程序都需要D库,当我们采用静态链接的方法链接程序时,最后内存中必定会有三份D库的内存,而采用动态链接的方法链接时,内存中只有一份D库的内容,三个程序共享该库。因此可以看出,使用静态链接的程序尺寸比较大,所占空间比较多,但是运行时不需要调入函数库。而采用动态链接的程序尺寸比较小,但是运行需要调入函数库,所用时间比较多。

以上就是读者理解的函数库,下面开始着手设计自己的一个函数库。这里我们将实现一个排序库,库里面有三个排序函数:冒泡排序、选择排序、插入排序。制作好的库我们放在 /usr/lib 目录下,声明这些函数的头文件放在 /usr/include 目录下。然后我们写一个测试函数调用这个库里面的函数。结果可以看出该库的使用方法和标准的C函数库一样。

制作过程如下:

1、编写函数库源代码:

/********************************** 文件名: sort.c** 创建者:linzi** 创建日期:2015-10-26** 文件说明:几种常见排序算法的源代码** Copyright: 2015-2020 Linzi ********************************/#include <stdio.h>#include "sort.h"/*********************************************************** 函数名:Bubble_Sort * 参数:data[]:待排序的数组,length:数组长度* 返回值:成功:0,失败:-1* 函数说明:冒泡法排序,将数组元素按从小到大排序**********************************************************/int  Bubble_Sort(int data[], int length){    int i = 0;    int j = 0; //   int tmp = 0;    if((data==NULL)||(length<0))    {    printf("array error or length error!\n");    return -1;    }    for(i=0;i<length-1;i++)    for(j=0;j<length-i-1;j++)        if(data[j]>data[j+1])        {       // tmp = data[j];       // data[j] = data[j+1];        //data[j+1] = tmp;        data[j] = data[j] ^ data[j+1];        data[j+1] = data[j] ^ data[j+1];        data[j] = data[j] ^ data[j+1];        }    return 0;}/*********************************************************** 函数名:Select_Sort * 参数:data[]:待排序的数组,length:数组长度* 返回值:成功:0,失败:-1* 函数说明:直接选择法排序,将数组元素按从小到大排序**********************************************************/int Select_Sort(int data[], int length){    int i = 0;    int j = 0;    int min = 0;    int k = 0;    for(i=0;i<length-1;i++)    {        k = i;        for(j=i+1;j<length;j++)            if(data[j]<data[k])                k = j;        if(k!=i)        {        data[i] = data[i]^data[k];     data[k] = data[i]^data[k];    data[i] = data[i]^data[k];          }       }}/*********************************************************** 函数名:Insert_Sort * 参数:data[]:待排序的数组,length:数组长度* 返回值:成功:0,失败:-1* 函数说明:直接插入法排序,将数组元素按从小到大排序**********************************************************/int Insert_Sort(int data[], int length){    int i = 0;    int j = 0;    int t = 0;    for(i=1;i<length;i++)    {        t = data[i];        for(j=i-1;j>=0&&data[j]>t;j--)        {            data[j+1]=data[j];        }        data[j+1] = t;    }}

2、编译函数库源文件:gcc -c sort.c -o sort.o

3、打包成静态链接库:ar cqs libsort.a sort.o

经过以上三步可以在目录中看到一个libsort.a 的文件将该文件复制到标准函数库目录:cp  libsort.a  /usr/lib

4、编写声明函数的头文件:事实上这一步并不是必须的,但是如果库函数中有些数据结构需要在头文件中声明时,这一步就不可或缺,为了让库的扩展性更好,笔者特意将头文件加上。下面为其代码:

#ifndef _SORT_H#define _SORT_Hint  Bubble_Sort(int data[], int length);int Select_Sort(int data[], int length);int Insert_Sort(int data[], int length);#endif
接着将该头文件放在编译器搜索的路径:cp  sort.h  /usr/include

经过以上步骤,我们就完成了一个静态链接库的制作。动态链接库的制作跟静态链接库的制作步骤基本一致,只是步骤3、打包成链接库所使用的命令不同,动态链接库的打包命令为:gcc -shared  -fPIC  sort.o -o libsort.so  .

至此,制作链接库的方法就介绍完成。下面写一小段测试代码测试一下链接库是否正常工作。

#include <stdio.h>//#include <sort.h>int main(int arc, char* argv[]){    int datas1[7];    int datas2[7];    int datas3[7];    int i = 0;    printf("input datas:\n");    for(i=0;i<7;i++)    scanf("%d",&datas1[i]);     Bubble_Sort(datas1,7);    for(i=0;i<7;i++)    printf("%d ",datas1[i]);     printf("\n");        printf("input datas:\n");    for(i=0;i<7;i++)    scanf("%d",&datas2[i]);     Select_Sort(datas2,7);    for(i=0;i<7;i++)    printf("%d ",datas2[i]);     printf("\n");        printf("input datas:\n");    for(i=0;i<7;i++)    scanf("%d",&datas3[i]);     Insert_Sort(datas3,7);    for(i=0;i<7;i++)    printf("%d ",datas3[i]);     printf("\n");        return 0;}

编译该程序:gcc test.c  -lsort.a  -o test 。这里我们要显式的调用函数库 :-lname ,因为编译器默认只链接C函数库。编译执行该代码可以得出正确结果。说明链接库正常工作。





0 0
原创粉丝点击