C++ 快速回顾(五)
- 前言
- 一、Dll和Lib的区别
- 区别
- 在开发中使用
- 二、封装并使用C++库
- 1.封装库
- 2.使用库
- 三、封装并使用C库
- 1.封装库
- 2.使用库
前言
用于快速回顾之前遗漏或者补充C++知识
一、Dll和Lib的区别
静态库(LIB)在编译时链接,代码被复制到可执行文件中。
动态库(DLL)在运行时链接,可执行文件只包含对 DLL 中函数的引用。
区别
文件分布:
静态库:可执行文件独立,不需要额外的库文件。
动态库:可执行文件需要依赖 DLL 文件。
更新和维护:
静态库:更新库需要重新编译程序。
动态库:更新 DLL 可以独立进行(但要保持接口兼容),程序无需重新编译。
内存占用:
静态库:每个使用库的程序都会在内存中有自己的一份库代码拷贝。
动态库:多个程序可以共享内存中的同一份 DLL 代码。
加载:
静态库:在程序启动时,代码已经被加载。
动态库:可以在程序启动时加载(隐式链接),也可以在程序运行时按需加载(显式链接,使用 LoadLibrary 和 GetProcAddress 函数)。
在开发中使用
静态库(LIB)的使用:
在项目配置中,需要指定静态库的路径和库文件名。链接时,链接器会将库中的代码直接整合到可执行文件中。
动态库(DLL)的使用:
需要两个文件:DLL 文件和导入库(.lib)。在链接时,使用导入库来解析符号,但代码不会复制到可执行文件。运行时,DLL 文件必须放在可执行文件的目录或系统路径中。
如何选择:
如果需要减少可执行文件的大小,方便更新,或者多个程序共享库代码,则使用 DLL。
如果希望程序独立运行,不依赖外部文件,则使用静态库。
二、封装并使用C++库
题外话:防止头文件被重复包含的两种方式
1.#pragma once
2.宏定义包裹,如下:
#ifndef INTERFACE_H
#define INTERFACE_H//TODO:#endif // !INTERFACE_H
1.封装库
定义导出宏
#define TESTCPP_API __declspec(dllexport)
整体的头文件如下,IInterface这个类加了导出宏就可以被导出给外界使用
具体的实现如下,FHello这个类没有加导出宏,我们只在内部使用导出后的DLL无法直接使用此类
如下代码就是将FHello这个类作为内部实现,然后提供CreateInterface 这个接口给外界调用,返回的是内部定义的类
在项目属性中分别选择Dll和Lib导出
会生成以下这些文件
我们最后实际上使用的只有如下这几个文件,头文件是方便我们调用函数等查看使用,具体的实现都在dll或者lib中了
2.使用库
有了上面导出的库文件,我们可以来使用了
我们新建控制台项目,导入之前生成的库文件到自定义的目录中
可以看到我们可以正常包含我们实现的内容
#include "dlllib/Interface.h"
#include <iostream>int main()
{IInterface* Interface = IInterface::CreateInterface();Interface->Init();printf(Interface->GetName());Interface->Destroy();system("pause");return 0;
}
但是这时候运行却运行不起来
我们需要根据需要设置此路径
此处有两种方式可以选择
第一种是直接在设置处设置即可
第二种是在代码中设置
在生成前把库拷贝到对应生成目录之下
xcopy /e /r /y $(ProjectDir)dlllib $(OutDir)
三、封装并使用C库
1.封装库
使用c来封装库时要注意
#ifdef __cplusplus
extern "C"
{
#endif
同时注意函数要使用 ** __stdcall** 写在要导出的函数前面,这个是函数压栈依次进行的标识
下面是具体的函数实现
2.使用库
使用的方式同上C++使用类库
可以看到只有CTEST_API导出宏的函数可以正常进行使用,不然会在运行时报错!!!