看大殖子阴阳怪气 發表於 2025-12-19 10:13:27

C++中显示与隐式加载dll的使用与区别

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>一、什么是 DLL?</li><li>二、隐式链接(Implicit Linking)</li><ul class="second_class_ul"><li>1. 原理</li><li>2. 使用步骤</li><li>3. 特点</li></ul><li>三、显式链接(Explicit Linking)</li><ul class="second_class_ul"><li>1. 原理</li><li>2. 使用步骤</li><li>3. 特点</li></ul><li>四、核心区别对比表</li><ul class="second_class_ul"></ul><li>五、如何选择?</li><ul class="second_class_ul"></ul><li>六、最佳实践建议</li><ul class="second_class_ul"></ul><li>七、补充:如何导出 DLL 函数?</li><ul class="second_class_ul"></ul><li>总结</li><ul class="second_class_ul"></ul><li>显示声明与隐式声明的使用与区别</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>一、什么是 DLL?</h2>
<p><strong>DLL(Dynamic Link Library)</strong> 是 Windows 下的动态链接库,包含可被多个程序共享的函数、资源或类。使用 DLL 可以实现代码复用、模块化设计和插件机制。</p>
<p>在 C++ 中,调用 DLL 中的函数有两种主要方式:</p>
<ol><li><strong>隐式链接(Implicit Linking)</strong></li><li><strong>显式链接(Explicit Linking)</strong></li></ol>
<p class="maodian"></p><h2>二、隐式链接(Implicit Linking)</h2>
<p class="maodian"></p><p class="maodian"></p><h3>1. 原理</h3>
<p>程序启动时自动加载 DLL,通过 <code>.lib</code> 导入库将 DLL 中的函数符号链接到可执行文件中。</p>
<p class="maodian"></p><p class="maodian"></p><h3>2. 使用步骤</h3>
<p>(1)准备三个文件:</p>
<ul><li><code>MyDll.dll</code>:动态库文件</li><li><code>MyDll.lib</code>:导入库(由 DLL 生成)</li><li><code>MyDll.h</code>:声明导出函数</li></ul>
<p>(2)头文件示例(MyDll.h)</p>
<div class="jb51code"><pre class="brush:cpp;">#ifdef __cplusplus
extern "C" {
#endif

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

#ifdef __cplusplus
}
#endif</pre></div>
<p>注意:<code>dllimport</code> 表示从 DLL 导入函数。</p>
<p>(3)链接&nbsp;<code>.lib</code>&nbsp;文件</p>
<p>在项目中添加 <code>.lib</code> 路径,并链接:</p>
<div class="jb51code"><pre class="brush:cpp;">#pragma comment(lib, "MyDll.lib")</pre></div>
<p>(4)直接调用函数</p>
<div class="jb51code"><pre class="brush:cpp;">#include "MyDll.h"

int result = Add(3, 4); // 直接像普通函数一样调用</pre></div>
<p class="maodian"></p><p class="maodian"></p><h3>3. 特点</h3>
<table><thead><tr><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>使用简单,像调用本地函数</td><td>启动时必须找到 DLL,否则程序无法启动</td></tr><tr><td>编译期检查函数签名</td><td>不支持动态选择或延迟加载</td></tr><tr><td>性能略高(无需查表)</td><td>难以实现插件系统或热更新</td></tr></tbody></table>
<p class="maodian"></p><h2>三、显式链接(Explicit Linking)</h2>
<h3>1. 原理</h3>
<p>运行时通过 <code>LoadLibrary</code> 和 <code>GetProcAddress</code> 手动加载 DLL 并获取函数地址。</p>
<h3>2. 使用步骤</h3>
<p>(1)不需要&nbsp;<code>.lib</code>&nbsp;文件,只需:</p>
<ul><li><code>MyDll.dll</code></li><li><code>MyDll.h</code>(知道函数原型)</li></ul>
<p>(2)加载 DLL 并获取函数指针</p>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;windows.h&gt;
#include &lt;iostream&gt;

// 定义函数指针类型
typedef int (*AddFunc)(int, int);

int main()
{
    HMODULE hDll = LoadLibrary(_T("MyDll.dll")); // 加载 DLL

    if (hDll == NULL) {
      std::cout &lt;&lt; "无法加载 DLL!" &lt;&lt; std::endl;
      return -1;
    }

    // 获取函数地址
    AddFunc Add = (AddFunc)GetProcAddress(hDll, "Add");
    if (!Add) {
      std::cout &lt;&lt; "无法找到函数 Add!" &lt;&lt; std::endl;
      FreeLibrary(hDll);
      return -1;
    }

    // 调用函数
    int result = Add(3, 4);
    std::cout &lt;&lt; "结果:" &lt;&lt; result &lt;&lt; std::endl;

    // 卸载 DLL
    FreeLibrary(hDll);
    return 0;
}</pre></div>
<h3>3. 特点</h3>
<table><thead><tr><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>运行时动态加载,灵活</td><td>使用复杂,需手动管理函数指针</td></tr><tr><td>可判断 DLL 是否存在,提供降级方案</td><td>无编译期检查,易出错(函数名拼错)</td></tr><tr><td>支持插件系统、热更新、按需加载</td><td>性能稍低(需查表)</td></tr><tr><td>程序可容忍缺失 DLL</td><td>需要正确处理&nbsp;<code>FreeLibrary</code>&nbsp;防止内存泄漏</td></tr></tbody></table>
<p class="maodian"></p><h2>四、核心区别对比表</h2>
<table><thead><tr><th>对比项</th><th>隐式链接</th><th>显式链接</th></tr></thead><tbody><tr><td>加载时机</td><td>程序启动时自动加载</td><td>运行时手动加载(LoadLibrary)</td></tr><tr><td>是否需要&nbsp;.lib</td><td>是</td><td>否(可选)</td></tr><tr><td>函数调用方式</td><td>直接调用(如&nbsp;Add(1,2))</td><td>通过函数指针调用</td></tr><tr><td>启动依赖</td><td>必须存在 DLL,否则无法启动</td><td>可容忍缺失,运行时报错</td></tr><tr><td>灵活性</td><td>低</td><td>高(可动态选择、卸载、替换)</td></tr><tr><td>适用场景</td><td>核心功能、稳定依赖</td><td>插件、可选模块、第三方组件</td></tr><tr><td>错误处理</td><td>启动失败</td><td>可在运行时提示用户</td></tr><tr><td>性能</td><td>略高</td><td>略低(需查找符号)</td></tr><tr><td>典型 API</td><td>无(编译器自动处理)</td><td>LoadLibrary,&nbsp;GetProcAddress,&nbsp;FreeLibrary</td></tr></tbody></table>
<p class="maodian"></p><h2>五、如何选择?</h2>
<table><thead><tr><th>场景</th><th>推荐方式</th></tr></thead><tbody><tr><td>程序核心功能依赖的 DLL(如运行库)</td><td>✅ 隐式链接</td></tr><tr><td>第三方 SDK、硬件驱动接口</td><td>✅ 显式链接(容错更好)</td></tr><tr><td>实现插件系统(如 Photoshop 滤镜)</td><td>✅ 显式链接</td></tr><tr><td>需要热更新或动态替换模块</td><td>✅ 显式链接</td></tr><tr><td>小项目、简单调用、DLL 一定存在</td><td>✅ 隐式链接更方便</td></tr></tbody></table>
<p class="maodian"></p><h2>六、最佳实践建议</h2>
<ul><li><strong>优先考虑显式链接</strong>&nbsp;用于第三方或可选模块,提升程序健壮性。</li><li>使用 RAII 封装&nbsp;<code>HMODULE</code>,避免忘记&nbsp;<code>FreeLibrary</code>:</li></ul>
<div class="jb51code"><pre class="brush:cpp;">class DllLoader {
public:
    DllLoader(const TCHAR* name) { hDll = LoadLibrary(name); }
    ~DllLoader() { if (hDll) FreeLibrary(hDll); }
    HMODULE get() { return hDll; }
private:
    HMODULE hDll = nullptr;
};</pre></div>
<ul><li>导出 C 函数(用&nbsp;<code>extern &quot;C&quot;</code>)避免 C++ 名称修饰问题。</li><li>在发布程序时,确保 DLL 路径正确(当前目录、系统路径、应用程序目录等)。</li></ul>
<p class="maodian"></p><h2>七、补充:如何导出 DLL 函数?</h2>
<div class="jb51code"><pre class="brush:cpp;">// MyDll.cpp
extern "C" __declspec(dllexport) int Add(int a, int b)
{
    return a + b;
}</pre></div>
<p><code>extern &quot;C&quot;</code> 防止 C++ 编译器名称修饰,便于 <code>GetProcAddress</code> 查找。</p>
<p class="maodian"></p><h2>总结</h2>
<table><thead><tr><th>方式</th><th>何时用</th><th>关键词</th></tr></thead><tbody><tr><td>隐式链接</td><td>简单、固定依赖</td><td>.lib、启动加载、直接调用</td></tr><tr><td>显式链接</td><td>灵活、容错、插件</td><td>LoadLibrary、GetProcAddress、运行时加载</td></tr></tbody></table>
<blockquote><p>💬 <strong>一句话总结:</strong></p>
<ul><li>要<strong>简单直接</strong>&nbsp;&rarr; 用&nbsp;<strong>隐式链接</strong></li><li>要<strong>灵活可控</strong>&nbsp;&rarr; 用&nbsp;<strong>显式链接</strong></li></ul></blockquote>
<p class="maodian"></p><h2>显示声明与隐式声明的使用与区别</h2>
<p><span><span>【C++】显示声明与隐式声明的使用与区别</span></span></p>
<p>到此这篇关于C++中显示与隐式加载dll的使用与区别的文章就介绍到这了,更多相关C++ 显示与隐式加载dll内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>C++动态加载so/dll库的实现</li><li>VC++ loadlibrary()加载三方dll失败, 返回错误码:126的解决方法</li><li>C++生成dll和调用dll的方法实例</li><li>C++调用C#的DLL实现方法</li><li>C++调用C#的DLL程序实现方法</li><li>C#调用C++版本dll时的类型转换需要注意的问题小结</li><li>c#调用c++的DLL的实现方法</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: C++中显示与隐式加载dll的使用与区别