一.分模块编程:
当我们在实现一个项目的时候,比如wifi小车,我们会碰到超声波模块,电机模块,wifi模块等模块的开发,这时候,我们可以让不同的小组成员来完成不同的模块,作为项目负责人只需要调用他们的模块函数即可。
所以分模块编程有以下优点:
a.功能责任划分
b.方便调试
c.主程序简洁
二.静态库与动态库
1.介绍
使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。
程序函数库可分为3种类型:静态函数库(static libraries)、共享函数库(shared libraries)、动态加载函数库(dynamically loaded libraries)
动态函数库同共享函数库是一个东西(在linux上叫共享对象库, 文件后缀是.so ,windows上叫动态加载函数库, 文件后缀是.dll)
2.区别
a) 静态库
静态函数库,是在程序执行前(编译)就加入到目标程序中去了 ;
优点: 运行快
发布程序无需提供静态库,因为已经在app中,移植方便
缺点:大
b) 动态库
动态函数库,是在程序执行时动态(临时)由目标程序去调用
缺点: 运行慢
优点: 小
三.库的制作
先来看一下整体的代码,这是一个计算器:
#include<stdio.h>
int add(int a,int b)
{
int c;
c=a+b;
return c;
}
int sub(int a,int b)
{
int c;
c=a-b;
return c;
}
int mul(int a,int b)
{
int c;
c=a*b;
return c;
}
float div(int a,int b)
{
float c;
c=(float)(a/b);
}
int main()
{
int x;
int y;
printf("input NO.1 data\n");
scanf("%d",&x);
printf("input NO.2 data\n");
scanf("%d",&y);
printf("add:%d+%d=%d\n",x,y,add(x,y));
printf("sub:%d-%d=%d\n",x,y,sub(x,y));
printf("mul:%dx%d=%d\n",x,y,mul(x,y));
printf("div:%d/%d=%f\n",x,y,div(x,y));
return 0;
}
来看一下运行结果:
我们把函数调用和主函数分开来试试(把函数调用封装成库)
静态库:
主函数
#include<stdio.h>
#include"func.c"
int main()
{
int x;
int y;
printf("input NO.1 data\n");
scanf("%d",&x);
printf("input NO.2 data\n");
scanf("%d",&y);
printf("add:%d+%d=%d\n",x,y,add(x,y));
printf("sub:%d-%d=%d\n",x,y,sub(x,y));
printf("mul:%dx%d=%d\n",x,y,mul(x,y));
printf("div:%d/%d=%f\n",x,y,div(x,y));
return 0;
}
~
函数:
int add(int a,int b)
{
int c;
c=a+b;
return c;
}
int sub(int a,int b)
{
int c;
c=a-b;
return c;
}
int mul(int a,int b)
{
int c;
c=a*b;
return c;
}
float div(int a,int b)
{
float c;
c=(float)(a/b);
}
头文件:
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
float div(int a,int b);
怎么把他们编译到一起呢
经过一系列操作我们会得到以下文件:
calculator.c 原程序
func.c 被调用的函数
func.h 头文件
mainStatic.c 主函数
我们要做的是把2.3.4给串联起来,首先主函数包含头文件
#include"func.h"
接下来是对func函数进行两步操作
a. gcc xxx.c -c 生成xxx.o文件
b. ar rcs libxxx.a xxx.o xxx.o文件生成xxx.a静态库文件
示例:
gcc func.c -c//生成func.o
ar rcs libfunc.a func.o //libfunc.a是生成的库,func.o是材料
接下来我们编译主函数,让主函数链库
gcc mainStatic.c -lfunc -L ./ -o main
//-lxxx就是连接哪个库,比如-lcurses就是调用ncurse图形库,-L./就是在当前路径下寻找库,不然会去/usr/lib里面找
编译完后我们会得到mian这个可执行文件,然后我们试一下,程序执行起来和原程序一样
动态库的制作:
首先我们做出func.so这个库
gcc -shared -fpic func.c -o func.so
-shared 指定生成动态库
-fpic 标准,fPIC 选项作用于编译阶段,在生成目标文件时就得使用该选项,以生成位置无关的代码。
然后我们编译主函数:
gcc mainDy.c -lfunc -L ./ -o mainDy
//mainDy.c就是主函数, 同样-lxxx链接库,然后在当前路径下连接,最后一个-o改一下名字
结果:
这里需要注意,一般来说这么写会报错,找不到库,因为系统默认是去/user/lib/里面去找的,由于该版本ubantu会自动帮我们去找到这个动态库所以没报错,但是在树莓派运行的linux上就会有报错,所以我们有什么解决办法呢
一般我们有这两种方法:
1.用超级用户权限(sudo)把编译好的.so库cp到/user/lib下面去(不建议)
2.更改环境变量:可以指定该程序运行时候,在LD_LIBRARY_PATH 所指定的路径去找库文件
export LD_LIBRARY_PATH="/xxx/xxx"
争对第二种方法,其实我们可以写一个脚本,即更改环境变量后再运行main函数的脚本:
export LD_LIBRARY_PATH="/home/CLC/Project3"
./mainDy
我们再用chmod +x给脚本文件加一个可执行权限,结果如下:
以上就是关于Linux静态库与动态库的相关概念以及编程,尚有不足之处,请各位大神指正。
salute CLC