调用c++_C/CPP|静态库与动态库的建立与调用

面对系统的复杂性和需求的变动性,分治和代码重用始终是代码组织首要考虑的因素。一个软件系统首先是一个多文件系统(隶属同一工程),并组织成库(函数库或类库)的形式,或者通过工程目录设置、#pragma comment(lib,"xxx.lib")语句来链接其它路径的库,最终通过链接器将所有文件链接为一个整体。在单一文件内部,也是通过函数或类对象来组织代码的。

对于库的链接可以有不同的时机,可以在编译阶段载入,也可以运行阶段载入(包括运行初始阶段的载入和运行时的按需载入),不同载入时机,各有优势。如静态库没有dll依赖,但动态库下的exe文件小,且可以动态更新。

Windows操作系统就是通过就是通过各种类型的库和小工具组合而成的。

库是写好后成熟的、可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。.lib、.dll是windows的库的后缀名。

所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:

3a2dc0e9875dace27a0bb284f2650a19.png

1 静态库

1.1 静态库生成

1.1.1 新建工程时选择静态库。

1.1.2 新建.h和.cpp文件:

// lib.h#ifndef __LIB__H__#define __LIB__H__int gcd(int a,int b);int add(int a,int b);#endif// lib.cpp#include "lib.h"int gcd(int a, int b){    if(a%b==0)        return b;    else        gcd(b,a%b);}int add(int a,int b){    return a+b;}

Linux下使用ar工具、Windows下vs使用lib.exe,将目标文件压缩到一起,并且对其进行编号和索引,以便于查找和检索。一般创建静态库的步骤如图所示:

77d1af2df34ba2c9a187b30d84f4aad0.png

1.1.2 编译、链接后会在Debug目录下生成.lib文件。此时需要使用的就是.h和.lib文件。

1.2 静态库使用

1.2.1 新建一个使用库的工程。

1.2.2 将.h和.lib文件复制到同一工程目录下或include目录下。

//libTest.cpp#include using namespace std;#include // 将.h和.lib复制到同一工程目录下#pragma comment(lib,"staticLib.lib")int main(){    cout<< gcd(350,770) <

如果不写#pragma comment(lib,"staticLib.lib"),则需要通过设置开发环境,将库文件及路径通过设置让链接器能够找到。

配置VS环境方式引入库文件.lib:

项目属性→配置属性→链接器→输入→附加依赖项:库名称。

如果.lib库文件不在源程序文件同级目录下,需要配置VS环境:

项目属性→配置属性→链接器→常规→附加库目录。

如果是VC6:

工程→设置→连接→输入→对象/库模块:库名称,如staticLib.lib。

工具→选项→目录:库文件目录,如F:WEBSITENOTESTESTSTATICLIB,也可以是相对路径。

2 动态库

2.1 动态库建立

2.1.1 新建工程,类型选择动态库。

2.1.2 新建以下.h和.cpp文件:

//mydll.hint fnTest(void);// mydll.cpp#include "stdafx.h"#include "mydll.h"BOOL APIENTRY DllMain( HANDLE hModule,                        DWORD  ul_reason_for_call,                        LPVOID lpReserved ){    return TRUE;}int fnTest(void){    return 100;}; mydll.def : Declares the module parameters for the DLL.LIBRARY      "mydll"DESCRIPTION  'mydll Windows Dynamic Link Library'EXPORTSfnTest// stdafx.cpp#include "stdafx.h"// stdafx.h#include 

编译后会生成.h、.lib、.dll文件。此处.lib文件为导入库,而并非静态链接库,其实际的执行代码位于动态库.dll中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息(记录了dll中函数的入口和位置,dll中是函数的具体实现)。而静态库中的lib包含了索引和实现。

也可以是以下代码样式:

// dllmain.cpp : Defines the entry point for the DLL application.#include "stdafx.h"BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved                     ){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:    case DLL_THREAD_ATTACH:    case DLL_THREAD_DETACH:    case DLL_PROCESS_DETACH:        break;    }    return TRUE;}//.h#pragma onceclass DynamicMath{public:    __declspec(dllexport) DynamicMath(void);    __declspec(dllexport) ~DynamicMath(void);    static __declspec(dllexport) double add(double a, double b);//加法    static __declspec(dllexport) double sub(double a, double b);//减法    static __declspec(dllexport) double mul(double a, double b);//乘法    static __declspec(dllexport) double div(double a, double b);//除法    __declspec(dllexport) void print();};

2.2 动态库引用或加载

2.2.1 动态库的静态调用(隐式加载)

.h和.lib加载方式与静态加载完全一致。但.dll文件必须放在环境变量指定的目录下。当然通常是与目标.exe文件放在一起。

如果在开发环境中直接运行程序,.h、lib和dll放到开发环境的当前目录下也行。

// dllStaticInclude.cpp,静态引用#include using namespace std;//DLL导出函数的头文件#include "mydll.h" // 将.h和.lib复制同一工程同一目录下或include目录下//DLL的导入库lib文件#pragma comment(lib, "mydll.lib")int main(){    cout<< fnTest() <

2.2.2 动态引用或加载

.dll文件放在环境变量指定的目录下,当然通常是与目标.exe文件放在一起。

利用LoadLibrary()函数进行加载。

// dllDynamicInclude.cpp,动态引用#include #include using namespace std;int main(){// ① 加载DLLHINSTANCE hModule = LoadLibrary("mydll.dll"); // dll要复制到相同路径下if (hModule == NULL){printf("mydll.dll加载失败");return 0;}typedef int (_cdecl *FUNTEST)(void); // 函数指针定义FUNTEST pfnTest;// ② 获得导出函数的地址pfnTest = (FUNTEST)GetProcAddress(hModule, "fnTest");// ③ 调用导出函数if (pfnTest != NULL){int nValue = (*pfnTest)(); printf("%d",nValue);}else{printf("LastError:%d");}//释放DLLFreeLibrary(hModule);    while(1);    return 0;}

按道理不需要.h头文件,但是前提是你知道接口是啥样的。

隐式加载和显示加载区别很明显,显示加载使用灵活,需要时加载,用完卸载,而隐式加载伴随着整个程序的生命周期。

3 总结一下

库分为静态库和动态库。静态库与可执行文件打包,动态库与可执行文件独立。静态库加载需要.lib和.h文件。动态库隐式加载需要.dll、.h、.lib文件,显示加载只需要.dll文件(由.h文件了解接口)。

ref

https://wwuhn.github.io/witisoPC/32cpp/C++/C++%E9%9D%99%E6%80%81%E5%BA%93%E4%B8%8E%E5%8A%A8%E6%80%81%E5%BA%93/a.html

https://wwuhn.github.io/witisoPC/32cpp/C++/C++%E9%9D%99%E6%80%81%E5%BA%93%E5%92%8C%E5%8A%A8%E6%80%81%E5%BA%93%E7%94%A8%E6%B3%95/a.html

-End-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值