|
1. 概述
在c语言的实际编程中,我们可以把完成某项功能的函数放在一个动态链接库里,然后提供给其他程序调用。
1.1 动态库
动态库是一种不可执行的二进制程序文件,它允许程序共享执行特殊任务所必需的代码和其他资源。Windows平台上动态链接库的后缀名是”.dll”,Linux平台上的后缀名是“.so”。Linux上动态库一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。
1.2 动态链接库的优点
复用性:DLL的编制与具体的编程语言以及编译器无关,不同语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数
可扩展性:DLL文件与EXE文件独立,只要接口不变,升级程序只需更新DLL文件不需要重新编译应用程序
节省内存:如果多个应用程序使用同一个dll,该dll的页面只需要存入内存一次,所有的应用程序都可以共享它的页面,从而节省内存
2. 生成动态链接库
仅对windows系统进行描述,下面以vs编译器为例:
在创建新项目中选择“动态链接库”
项目的命名就是最后dll的名字,新建h和cpp文件
main.cpp
#include "main.h"
#include <stdio.h>
/* 输入年月日计算一年中第几天 */
int Day_of_year(int year, int month, int day)
{
int sum,leap;
switch(month) // 先计算某月以前月份的总天数
{
case 1:sum=0;break;
case 2:sum=31;break;
case 3:sum=59;break;
case 4:sum=90;break;
case 5:sum=120;break;
case 6:sum=151;break;
case 7:sum=181;break;
case 8:sum=212;break;
case 9:sum=243;break;
case 10:sum=273;break;
case 11:sum=304;break;
case 12:sum=334;break;
default:printf(&#34;data error&#34;);break;
}
sum=sum+day; // 再加上某天的天数
if(year%400==0||(year%4==0&&year%100!=0)) {// 判断是不是闰年
leap=1;
} else {
leap=0;
}
if(leap==1&&month>2) { // *如果是闰年且月份大于2,总天数应该加一天
sum++;
}
return sum;
}
Main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
#ifdef __cplusplus
#define EXPORT extern &#34;C&#34; __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif // __cplusplus
EXPORT int Day_of_year(int year, int month, int day);
#endif // __MAIN_H__
编译成功后在bin\Debug目录下生成3个文件:dll.dll,libdll.a,libdll.def
3. 调用动态链接库
新建工程,把dll.dll拷贝到新工程的bin\Debug目录下
main.c
#include <stdio.h>
#include <windows.h>
typedef int(*Getday)(int, int, int); //定义函数类型
HINSTANCE hDll; //DLL句柄
Getday getday;
int main()
{
hDll = LoadLibrary(&#34;dll.dll&#34;); //加载 dll
getday = (Getday)GetProcAddress(hDll, &#34;Day_of_year&#34;);//通过指针获取函数方法
printf(&#34;day = %d\n&#34;, getday(2015, 10, 1) );//调用函数
FreeLibrary(hDll);//释放Dll句柄
system(&#34;pause&#34;);
return 0;
}
编译就可以使用,当dll程序升级时,只需要替换dll,而不用重新编译exe
4. 调试案例
1)错误一
/tmp/ccMpgzNu.o: In function `main&#39;:
test.c:(.text+0x13): undefined reference to `dlopen&#39;
test.c:(.text+0x1c): undefined reference to `dlerror&#39;
test.c:(.text+0x53): undefined reference to `dlsym&#39;
test.c:(.text+0x63): undefined reference to `dlerror&#39;
test.c:(.text+0x89): undefined reference to `dlclose&#39;
test.c:(.text+0xc7): undefined reference to `dlclose&#39;
collect2: error: ld returned 1 exit status
解决方案:
头文件添加:#include <dlfcn.h>
编译选项加上- ldl,即 gcc -o test test.c -ldl ,网上有gcc -ldl -o test test.c,这种方式也是会报这个错误的
2)错误二
error while loading shared libraries: libtiger.so: cannot open shared object file: No such file or direct
我的这段代码里则会打印Load lib.so failed!
解决方案:
在程序代码里配置路径void *pdlHandle = dlopen(“libday.so”, RTLD_LAZY);
将动态链接库配上路径,如 ./libday.so表示可执行文件与链接库同一路径
将动态链接库的目录放到程序搜索路径中,可以将库的路径加到环境变量
export LD_LIBRARY_PATH=pwd:$LD_LIBRARY_PATH(pwd带反撇号的哈)
拷贝libday.so到绝对目录 /lib |
|