千家信息网

C++ 中的动态库和静态库(Windows)

发表于:2024-10-27 作者:千家信息网编辑
千家信息网最后更新 2024年10月27日,库:在C/C++中,使用库(Library)的技术,可以将编译好的符号提供给第三方使用。库有两种:1、动态库 Dynamic-Link Library (DLL) (Linux下叫做 Shared L
千家信息网最后更新 2024年10月27日C++ 中的动态库和静态库(Windows)

库:

在C/C++中,使用库(Library)的技术,可以将编译好的符号提供给第三方使用。

库有两种:

1、动态库 Dynamic-Link Library (DLL) (Linux下叫做 Shared Library)

2、静态库 Static Library


一、动态库的创建和使用


创建DLL:

用VC创建一个类型为 "dll"的控制台项目,VC会自动创建DLL的项目框架

它自动生成一个DllMain函数,可以类比普通应用程序中的main函数


VC项目设置:

1、取消"预编译头文件"

2、改为 "/MTd编译"

3、修改输出的DLL的名字 (my.dll)



编译,得到 *.lib 和 *.dll,其中:

*.dll:

包含所有代码编译成的指令


*.lib:包含一个列表,表名my.dll中含有哪些符号,每个符号对应在dll中的位置。(被导出的符号)


所以,*.lib比*.dll的文件体积小得多





如果想导出一个全局函数,就用关键字 __declspec(dllexport)来声明

注意:这是VC平台特有的关键字,在linux平台下不可用

使用如下:

template __declspec(dllexport) void MySwap(T& obj1, T& obj2){        T tmp = obj1;        obj1 = obj2;        obj2 = tml;}



使用dll:

#pragma  comment(lib, "12_18_DLL01")__declspec(dllimport) int Add(int a, int b);int main(){        int ret = Add(1, 2);        std::cout << ret << std::endl;        return 0;}

但这个地方我发现了一个问题:

__declspec(dllimport) int Add(int a, int b);

这行代码表示导入dll文件中的符号

但一开始我错误得写成了 export, 结果居然仍然是正确的

没有深究,初步推测是编译器优化了 (IDE: VS2015),甚至不写前面的关键字,直接写成函数的声明,程序也是能正确执行的


DLL的部署位置:

1、可执行文件所在目录

2、进程当前目录

3、系统目录 (C:\Windows\System32\ 和 C:\Windows\System\)

4、Windows目录 (C:\Windows\)

5、环境变量 PATH 中的目录



通过初步接触DLL的发布和使用,相比普通的声明、定义,会发现DLL有以下作用:

1、隐藏了代码

2、公开了功能


当然,DLL的作用远不止如此





二、DLL的加载和卸载


DLL的加载:

DLL不能独立运行,只有当 *.exe 被运行时, *.dll 才会被加载运行。

在exe文件中有一些标识信息,表示该 exe 依赖哪些 dll 文件,操作系统据此去寻找、加载相应的dll文件。

exe 被加载到内存,形成一个进程 process,dll也被加载到内存,进程可以直接调用DLL中的函数(Code)


数据段和代码段:

在dll文件中,至少分为两个段:

1、代码段:

存储指令(函数体)

2、数据段:

数据段,存放全局变量

当 *.dll 被加载时,代码段只被加载一次,是公共的。

数据段被每个程序各自拷贝一份,是私有的



三、DLL中的动态内存管理

在dll中申请的动态内存,必须在dll中释放,否则会导致内存泄漏 (这是由Windows自己的特点决定的)



四、DLL中使用头文件

按照惯例,由模块的作者提供头文件,头文件中应该用类型、函数声明。

所以,我们在创建DLL时,应该附带一份头文件,而不是让使用者自己去写函数声明。


五、DLL中导出一个类

导出类的定义,其实就是导出其成员函数

类的声明格式:

class __declspec(dllimport) MyClass{};


六、静态库的概念及使用


静态库:

static library,仅一个 *.lib 文件

静态库中直接就含有代码段和数据段,在链接过程中,是直接把里面的东西链接过来,形成完整的可执行程序

exe运行的时候不依赖 .lib 文件


创建:

1、建立一个新工程,工程类型为:静态库

2、不需要其他设置,直接编译链接生成,得到 *.lib文件


使用:

#pragma comment(lib, "MyLib.lib")int MyAdd(int a, int b);    //通常发布会把把声明放到头文件中,一并发布


静态库的注意事项:

1、静态库的使用不太方便:

如果该静态库是VS2008编译的,那么APP也得用VS2008编译,版本必须一致

此外,运行时库(/MT、/MTd、/MD、/MDd)也必须要一致

因此可以看出,静态库的使用,约束条件是比较多的


静态库和动态库的对比:

静态库优点:

使用静态库,最后得到的可执行程序执行时对这个库不再依赖


动态库优点:

便于升级更新,只要保持接口不变,可以通过更新DLL来升级程序,而不需要重新编译程序


目前通常都使用动态库


但动态库也存在更多的安全方面的隐患,毕竟如果有人恶意替换DLL(能做到这一步的人往往是软件团队的内部人员),程序的执行将会违背编程者的本意.......


七、DLL的手动加载

之前加载DLL的方式是自动加载。

自动加载和手动加载:

1、自动加载

在编译时指定dll,则当exe程序启动运行时,首先加载相关的dll

(DLL在程序执行前被加载,在程序结束后被卸载)


2、手动加载

在编译时不指定dll,在运行时调用LoadLibrary来加载dll

(这样做,可以自己决定什么时候加载、什么时候卸载DLL)



手动加载的方式:

#include #include 

使用 LoadLibrary 来加载dll,

使用 FreeLibrary 来卸载dll,

它提供了一种在运行时手动加载dll的技术手段,增加了编程的灵活性

(只要有*.dll就可以,也不需要 *.lib 和 *.h )


对DLL的要求:

1、要求待调用的函数按"C"方式编译(符号名即函数名)

extern "C" __declspec(dllexprot) int MyAdd(int a, int b);

2、dll文件放在可被系统搜索到的路径


代码:

#include #include #include int main(){        wchar_t* Path = L"12_18_DLL01.dll";        HINSTANCE  handle = LoadLibrary(Path);      // 字符集兼容问题        if (handle)        {                // 定义要找的函数原型                typedef int(*DLL_FUNCTION_ADD) (int, int);                // 找到目标函数的地址       注意实现必须用 extern "C" 的方式编译                DLL_FUNCTION_ADD dll_func = (DLL_FUNCTION_ADD)GetProcAddress( handle, "Add");                if (dll_func)                {                        // 调用该函数                        int result = dll_func(1, 2);                        std::cout << result << std::endl;                }        }        FreeLibrary(handle);        return 0;}


八、项目的静态编译

有一种场景,将以往VS生成的 *.exe 程序拷贝到其他 没有VS运行环境的机器上,这时候程序往往是无法运行的,这是因为,VC编译默认采用动态编译的方式,因此 要么给这个机器也安装一套运行环境,要么采用静态编译的方式生成可执行文件(*.exe)

静态编译后的程序,将会包含一切程序运行时所依赖的环境


对VC来说:

静态编译:

/MT /MTd


动态编译:

/MD /MDd




动态编译和静态编译的比较:

1、动态编译不方便发布,但生成的可执行文件体积较小

2、静态编译方便发布,但生成的可执行文件体积较大



编译 文件 静态 程序 函数 动态 运行 代码 方式 生成 内存 手动 数据 目录 符号 环境 项目 体积 关键 关键字 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 搭建云桌面办公服务器k8s 软件开发周例会开会发言模板 吉利远景3音乐数据库初始化 网络安全自查表责任部门 如何在线培训软件开发 联影智能数据库 机场网络安全措施 网络安全黑板报模板简单大全集 网络方向和软件开发方向 php的软件开发工具包 上海软件开发有限公司 mc玩家炸迷你世界服务器房间 企业电商软件开发价钱 湖南地区软件开发公司电话 计算机系统集成和软件开发 信用卡逾期上报金融基础数据库 市网络安全应急管理中心怎么样 ios地图软件开发 小米软件开发面试 新枫之谷服务器可以转几个 数据库数据 提取 网络安全和信息化调查报告 我的世界新开的纯净生存服务器 宁波优享汇互联网科技有限公司 sll错误无法安全与服务器连接 健康码计算机网络技术 计算机网络技术期末试题 数据库的敏感技术 没有服务器怎么上传文件 免费服务器运行代码
0