为了代码的共享和可重用,将一些需要反复使用的代码制作成库文件,有两种类型的库文件:静态库和动态库。
静态库和动态库是两种共享程序代码的方式,它们的区别是:静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。
使用静态库文件,在链接过程中,将库内的代码完整进行拷贝复制到程序中,生成EXE可执行文件,优点是,EXE可以脱离环境执行,(一次编译,处处执行),因为已包含所有的lib代码。缺点是,可扩展性差,当lib功能扩展之后,需要重新编译链接EXE文件。以及多次使用lib就会有多分冗余的拷贝。
·································Windows下·······························
制作与使用函数 和类 的静态库
制作:第一步 建立static library工程
第二步 头文件申明函数,或者类。 源文件中实现函数体,或者类方法。(除模板类不支持实现定义的分开)
第三步 编译 链接 在工程路径/debug/下 生成 .lib 文件
使用:第一步 包含库文件的头文件(用户知道了如何调用,但不知道具体实现)
第二步 库lib文件 放入控制台的工程路径下
第三步 引入#pragma comment (lib,"静态库文件名“) //没有分号
第四步 编译 链接 执行生成.exe文件(一次编译,处处执行)
制作与使用函数的动态库
制作:第一步 建立Dynamic_link library 工程
第二步 头文件申明函数,若申明成普通函数,则只可在当前工程下调用,相当于动态库的内部函数
若申明成导出函数,除生成.dll文件外,还生成相应的.lib文件,供外部调用
第三步 编译链接 生成.dll以及.lib文件
使用:静态加载 (需动态库中的函数为导出函数 ——declspec(dllexport) )
第一步 将.dll 以及.lib以及.h文件包含在控制台工程中。
第二步 引入#pragma comment (lib,"静态库文件名“) //没有分号
第三步 编译 链接 执行生成.exe文件(若脱离此dll以及.lib所在的工作环境,.exe则不能执行)
动态加载 (#include<windows.h>需要求函数声明为c编译方式的导出函数 extern "c" int __declspec(dllexport)add(int a,int b) ,则此函数用c方式编译,不能重载)
第一步 将.dll文件以及.h文件包含在控制台工程中。
第二步 创建句柄
第三步 加载动态库 LoadLibrary("动态库文件名“)
第四步 获取动态库内的函数 使用句柄接收 GetProcAddress(句柄名,"函数名");
第五步 使用句柄调用函数
第六步 卸载动态库 FreeLibrary(句柄)
示例:
动态库内容:
使用动态库的控制台工程源文件:
#include "test.h"
#include <iostream>
#include <Windows.h>
using namespace std;
typedef int(*pfun)(int, int);//定义一个函指针 int(*padd)(int, int)
int main()
{
HINSTANCE hdll;
hdll = LoadLibrary("test_dll.dll");
if (hdll == NULL)
{
cout << "load library error!" << endl;
return;
}
pfun padd= (pfun)GetProcAddress(hdll, "add");
if (padd == NULL)
{
cout << "get fun error!" << endl;
}
else
{
cout << "add(2,3):" << padd(2, 3) << endl;
}
FreeLibrary(hdll);
}
若出现:error C2664: “HMODULE LoadLibraryW(LPCWSTR)”: 无法将参数 1 从“const char [13]”转换为“LPCWSTR”错误
原因 :工程只支持UNICODE字符
解决方法:
1、工程属性->配置属性-->常规--->字符集---->使用多字节符字符集
|
结果:add(2,3):5
制作与使用全局变量 的动态库
制作:在动态库工程中
第一步 头文件中申明导出全局变量
第二步 源文件中定义全局变量
第三步创建模块定义文件 文件名与动态库文件名相同 后缀为.def
第四步 将test_dll.def加载到动态库工程中,编译链接生成.dll和.lib文件
使用: 在控制台工程中
第一步 静态加载动态库#pragma comment(lib,"test_dll.lib")
第二步申明导入动态库中的全局变量extern int —declspec(dllimport) g_global;
第三步使用时 g_global只代表一个地址 需强转成指针再解引用
制作与使用类的动态库
制作:在动态库工程中
第一步 头文件中申明为导出类 class __declspec(dllexport)stack
第二步 源文件中实现类方法 则素有的方法都为导出方法
第三步 编译链接生成.dll .lib文件
使用:在控制台工程中
第一步 将.dll .lib .h包含在工程目录下
第二步 静态加载动态库 #pragma comment(lib,"test_dll.lib")
第三步 直接用!
示例:
头文件:
class __declspec(dllexport)stack
{
public:
stack(int sz);
~stack();
public:
bool push(int a);
bool pop();
bool isfull()const;
bool isempty()const;
bool show();
private:
int *data;
int top;
int size;
};
源文件:
#pragma comment(lib,"test_dll.lib")
//extern int __declspec(dllimport) g_global;
void main()
{
stack s(5);
s.push(1);
s.push(2);
s.push(3);
s.show();
}
动态库中源文件:
#include <iostream>
#include "test.h"
using namespace std;
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a*b;
}
int g_global = 10;
bool stack::isfull()const
{
return top >= size;
}
bool stack::isempty()const
{
return top == 0;
}
stack::stack(int sz)
{
size = sz;
data = new int[size];
top = 0;
}
stack::~stack()
{
delete[]data;
data = NULL;
size = top = 0;
}
bool stack::push(int a)
{
if (isfull())
{
return false;
}
data[top++] = a;//先赋值后++
return true;
}
bool stack::pop()
{
if (isempty())
return false;
top--;
return true;
}
bool stack::show()
{
for (int i = 0; i < top; ++i)
{
cout << data[i] << endl;
}
return true;
}