Windows的静态库与动态库
Windows的静态库与动态库
1.静态库
1.1 静态库特点
- 运行不存在
- 静态库源码被链接到调用程序中
- 目标程序的归档
1.2 C语言静态库
- C静态库的创建
- 创建一个静态库项目。
- 添加库程序,源文件使用C文件。
int Clib_add(int add1,int add2){
return add1+add2;
}
int Clib_sub(int sub1,int sub2){
return sub1 - sub2;
}
- C静态库的使用
- 库路劲设置:可以使用pragma关键字设置
-
pragma comment(lib,”../lib/clib.lib”)
#pragma comment(lib,"../Debug/Clib.lib")
#include <stdio.h>
#include <process.h>
int main(){
int sum,sub;
sum = Clib_add(5,3);
sub = Clib_sub(5,3);
printf("sum=%d,sub=%d\n",sum,sub);
system("pause");
return 0;
}
1.3 C++语言静态库
- C++静态库的创建
- 创建一个静态库项目
- 添加库程序,源文件使用cpp文件
int CPPlib_add(int add1,int add2){
return add1 + add2;
}
int CPPlib_sub(int sub1,int sub2){
return sub1 - sub2;
}
- C++静态库的使用
- 库路径设置:可以使用pragma关键字设置
-
pragma comment(lib,”../lib/cpplib.lib”)
#include <iostream>
using namespace std;
//给链接器看
int CPPlib_add(int add1,int add2);
int CPPlib_sub(int sub1,int sub2);
//给编译器看
#pragma comment(lib,"../Debug/CPPlib.lib") //?CPPlib_add@@YAHHH@Z / ?CPPlib_sub@@YAHHH@Z
extern "C" int Clib_add(int add1,int add2);
extern "C" int Clib_sub(int sub1,int sub2);
#pragma comment(lib,"../Debug/Clib.lib") //Clib_add / Clib_sub
int main(){
//调c++库函数
int sum = CPPlib_add(5,4); //?CPPlib_add@@YAHHH@Z
int sub = CPPlib_sub(5,4); //?CPPlib_sub@@YAHHH@Z
cout << "sum=" << sum << ",sub=" << sub << endl;
//调c库函数
sum = Clib_add(5,3); //?Clib_add@@YAHHH@Z 使用extern "C",编译时不换函数名-->Clib_add
sub = Clib_sub(5,3); //?Clib_sub@@YAHHH@Z -->Clib_sub
cout << "sum=" << sum << ",sub=" << sub << endl;
system("pause");
return 0;
}
2.动态库
2.1 动态库特点
-
动态库的特点
- 运行时独立存在
- 源码不会链接到执行程序
- 使用时加载(使用动态库必须使动态库执行)
-
与静态库的比较
-
由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多分代码,所以代码体积会增大。动态库的代码只需要存在一份,其他程序通过函数地址使用,所以代码体积小。
-
静态库发生变化后,新的代码需要重新链接嵌入到执行程序中。动态库发生变化后,如果库中函数的定义(或地址)未变化,其他使用DLL的程序不需要重新链接。
-
2.2动态库创建
-
创建动态库项目
-
添加库程序
-
库程序导出 – 提供给使用者库中的函数等信息。
- 声明导出:使用_declspec(dllexport)导出函数
注意:动态库编译链接后,也会有LIB文件,是作为动态库函数映射使用,与静态库不完全相同。
制作动态库
_declspec(dllexport) int CPPdll_add(int add1,int add2){ return add1 + add2; } _declspec(dllexport) int CPPdll_sub(int sub1,int sub2){ return sub1 - sub2; } _declspec(dllexport) int CPPdll_mul(int mul1,int mul2){ return mul1 * mul2; }
动态库原理图
- 模块定义文件:.def
例如:LIBRARY DLLFunc //库
EXPORTS //库导出表
DLL_Mul @1 //导出的函数
不加声明导出
int CPPdll_add(int add1,int add2){ return add1 + add2; } int CPPdll_sub(int sub1,int sub2){ return sub1 - sub2; } int CPPdll_mul(int mul1,int mul2){ return mul1 * mul2; }
添加模块定义导出文件
LIBRARY CPPDll EXPORTS CPPdll_add @1 CPPdll_sub @2 CPPdll_mul @3
2.3动态库的使用
-
隐式链接(操作系统负责使动态库执行)
-
头文件和函数原型
可以在函数原型的声明前,增加_declspec(dllimport)
-
导入动态库的LIB文件
-
在程序中使用函数
-
隐式链接的情况,dll文件可以存放的路径:
- 与执行文件中同一个目录下(建议放在此目录下)
- 当前工作目录
- Windows目录
- Windows/System32目录
- Windows/System
- 环境变量PATH指定目录
#include <iostream> using namespace std; _declspec(dllimport)int CPPdll_add(int add1,int add2); _declspec(dllimport)int CPPdll_sub(int sub1,int sub2); _declspec(dllimport)int CPPdll_mul(int mul1,int mul2); //通知链接器到哪抓编号和dll文件名(CPPDll.dll) #pragma comment(lib,"../Debug/CPPDll.lib") int main(){ int sum = CPPdll_add(5,4); int sub = CPPdll_sub(5,4); int mul = CPPdll_mul(5,4); cout << "sum=" << sum << ",sub=" << sub << ",mul=" << mul << endl; system("pause"); return 0; }
-
-
显示链接(程序员自己负责使动态库执行)
-
定义函数指针类型 typedef
-
加载动态库
HMODULE LoadLibrary( LPCTSTR lpFileName //动态库文件名或全路劲 ); //返回DLL的实例句柄(HINSTANCE)
-
获取函数地址
FARPROC GetProcAddress( HMODULE hModule //DLL句柄 LPCSTR lpProcName //函数名称 ); //成功返回函数地址
-
使用函数
-
卸载动态库
BOOL FreeLibrary( HMODULE hModule //DLL的实例句柄 );
#include <iostream> #include <Windows.h> using namespace std; typedef int(*FUNC)(int m,int n); int main(){ HINSTANCE hDll = LoadLibrary("CPPDll.dll"); cout << "hDll:" << hDll << endl; FUNC add = (FUNC)GetProcAddress(hDll,"CPPdll_add"); cout << "addAdress:" << add << endl; int sum = add(5,4); cout << "sum:" << sum << endl; FUNC sub = (FUNC)GetProcAddress(hDll,"CPPdll_sub"); cout << "subAdress:" << sub << endl; int su = sub(5,4); cout << "sub:" << su << endl; FUNC mul = (FUNC)GetProcAddress(hDll,"CPPdll_mul"); cout << "mulAdress:" << mul << endl; int mu = mul(5,4); cout << "mul:" << mu << endl; system("pause"); FreeLibrary(hDll); return 0; }
-
2.4动态库中封装类
-
在类名称前增加_declspec(dllexport)定义,例如:
class _declspec(dllexport) CMath{ ... };
-
通常使用预编译开关切换类的导入导出定义,例如:
#ifdef DLLCLASS_EXPORTS #define EXT_CLASS _declspec(dllexport) //dll #else #definE EXT_CLASS _declspec(dllimport) //使用者 #endif class EXT_CLASS CMath{ ... };
例子:
头文件
#ifndef _ClASSDLL_H #define _CLASSDLL_H #ifdef DLLCLASS_EXPORTS #define EXT_CLASS _declspec(dllexport) //dll #else #define EXT_CLASS _declspec(dllimport) //使用者 #endif class EXT_CLASS CMath{ public: int add(int m,int n); int sub(int m, int n); }; #endif
源文件
#define DLLCLASS_EXPORTS #include "ClassDll.h" int CMath::add(int m,int n){ return m + n; } int CMath::sub(int m,int n){ return m - n; }
调用动态库中的封装类
#include "..\ClassDll\ClassDll.h" #include <iostream> using namespace std; #pragma comment(lib,"../Debug/ClassDll.lib") int main(){ CMath myMath; int sum = myMath.add(5,4); int sub = myMath.sub(5,4); cout << "sum=" << sum << ",sub=" << sub << endl; system("pause"); return 0; }