我们平时所做的大部分开发都是二次开发,会使用卖方提供的SDK,SDK中只有接口,没有具体业务逻辑实现的代码,我们在SDK接口的基础上做开发,进而实现我们想要的功能。
首先我们来说说静态链接库和动态链接库,静态链接库往往以lib后缀结尾,动态链接库往往以dll后缀结束,但是我们不能仅仅以后缀名作为它们二者的区别。比如动态链接库也存在lib后缀的文件,但是此时的lib文件只是保存一些函数符号,运行代码的指令部分仍然存在在dll文件中,也就是说动态链接库中的lib相当于在函数符号符函数入口地址之间建立映射关系。其实从本质上来说,动态链接库是我们在运行程序的时候才进行链接,同一个dll可以被多个程序链接使用,所以我们使用动态链接库生成最终的程序后,如果将该动态链接库文件删除,程序运行时将提示缺少对应dll文件的错误。
静态链接库的代码指令是直接包含在最终的应用程序中,使用静态链接库生成的最终程序里,我们直接删除静态链接库文件,程序仍然将正常执行。因为在生成程序的过程中,静态链接库中的代码指令已经完全的嵌入到了应用程序中了。windows提供的大多数服务都是以dll形式提供的。然而静态链接库虽然可移植性强,但是会造成程序很庞大,所以往往大多数开发接口都是以动态链接库的形式提供的。
Windows
动态链接库程序
DllDiamond.h
#ifndef DLLDIAMOND_H_
#define DLLDIAMOND_H_
#ifdef __cplusplus
extern "C"
{
#endif //end of #ifdef __cplusplus
__declspec(dllexport) void diamond(int n);
#ifdef __cplusplus
}
#endif //endof #ifdef __cplusplus
#endif //endof #ifndef DLLDIAMOND_H_
DllDiamond.cpp
#include <stdio.h>
#include "DllDiamond.h"
//棱形占(2n+1)行(2n+1)列
void diamond(int n)
{
int row = 0;
int column = 0;
//上下对称
for (; row < 2*n+1; ++row)
{
//左右对称
for (column = 0; column < 2*n+1; ++column)
{
//以(0,0)为原点,column为x轴(向右为正方向),row为y轴(向下为正方向)
if (row == column + n || row == column - n ||
row == -column + n || row== -column + 3*n)
{
printf("*");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
动态链接库调用程序
将上面动态链接库程序生产的.lib文件和.dll文件拷贝到使用模块的工程目录下,当然还有DllDiamond.h头文件。
//动态链接库调用模块程序
#if 1
#include "DllDiamond.h"
#include <cstdio>
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#define ERREOF -1
//将链接库链接到程序中
#pragma comment(lib, "DllDiamond.lib")
int main(int argc, char **argv)
{
intnLine = 0;
charstatus = ' ';
while(1)
{
cout<< "请输入打印菱形行数: ";
cin>> nLine;
diamond(nLine);
fflush(stdin);
cout<< "是否继续打印菱形?(y or n)";
while(ERREOF == scanf("%[yYnN]", &status))
{
cout<< "输入非法,请继续输入: ";
}
scanf("%*c");//接收输入缓冲区中的换行符
if('Y' != status && 'y' != status)
{
break;
}
}
return0;
}
#endif
程序运行结果:
将链接文件连接到程序中的方式有三种:
第一种:#pragma comment(lib, "DllDiamond.lib")
第二种:
第三种:手动加载动态连接库,导入待使用的函数
#if 1
#include "DllDiamond.h"
#include <cstdio>
#include <iostream>
#include <windows.h>
using std::cin;
using std::cout;
using std::endl;
#define ERREOF -1
//将链接库链接到程序中
//#pragma comment(lib,"DllDiamond.lib")
//给函数指针取一个别名
//typedef void (*DiamondProc)(int);
typedef void (__cdecl *DiamondProc)(int);
int main(int argc, char **argv)
{
intnLine = 0;
charstatus = ' ';
//定义实例句柄对象
HINSTANCEhInst = NULL;
//手动加载动态链接库Dll
hInst= LoadLibrary("DllDiamond.dll");
//获取Dll的导出函数
DiamondProcfunc = (DiamondProc)GetProcAddress(hInst,"diamond");
while(1)
{
cout<< "请输入打印菱形行数: ";
cin>> nLine;
//调用动态链接库函数
func(nLine);
fflush(stdin);
cout<< "是否继续打印菱形?(y or n)";
while(ERREOF == scanf("%[yYnN]", &status))
{
cout<< "输入非法,请继续输入: ";
}
scanf("%*c");//接收输入缓冲区中的换行符
if('Y' != status && 'y' != status)
{
break;
}
}
//手动卸载动态链接库Dll
FreeLibrary(hInst);//释放Dll函数
hInst= NULL;
return0;
}
#endif
Linux
动态库程序
#include <stdio.h>
//棱形占(2n+1)行(2n+1)列
void diamond(int n)
{
int row = 0;
int column = 0;
//上下对称
for (; row < 2*n+1; ++row)
{
//左右对称
for (column = 0; column < 2*n+1; ++column)
{
//以(0,0)为原点,column为x轴(向右为正方向),row为y轴(向下为正方向)
if (row == column + n || row == column - n ||
row == -column + n || row== -column + 3*n)
{
printf("*");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
动态链接库使用程序
#include <stdio.h>
int main()
{
int n = 0;
printf("请输入n值:");
scanf("%d", &n);
diamond(n);
return 0;
}
注意:上面的操作只是产生了动态链接库文件和将动态链接库文件链接到调用程序中,但是执行./a.out时会报错,说找不到链接的文件。这个问题可以有三种解决办法,分别如下:
①export LD_LIBRARY_PATH=.
设置环境变量LD_LIBRARY_PATH的值为当前目录,链接的时候会在当前目录中寻找链接文件
②将生成的动态链接库文件拷贝到“/usr/lib/”目录下
链接的时候会在“/usr/lib”目录下寻找链接文件
③切换到超级用户,在“/etc/ld.so.conf.d/”目录下随便建一个“.conf”格式的文件,将链接的动态库文件所在的目录绝对路径写在该文件中并保存,之后再调用“ldconfig”shell命令刷新一下即可。
博主在这里对动态链接库的使用做了一个简单的总结,主要是是以笔记的形式体现,希望对初学Dll编程的小伙伴有一点帮助。在Linux上的动态链接库程序,博主不是很规范,主要是在于展示如何生成动态链接库文件、编译链接动态链接库文件、以及运行时加载动用链接库时的常见问题解决。聪明的小伙伴们,相信你们已经掌握了动态链接库的使用方法了。关于静态链接库的使用将作为下一篇的总结内容,这里就不再续说了,以免篇幅过长,也不利于小伙伴们学习和实践。