VS中动态库(外部库)导出与使用

在 C++ 中,动态库(Dynamic Link Library, DLL)允许模块化开发,运行时加载共享代码。以下是 动态库的导出与使用 的详细步骤:


1. 动态库(DLL)的导出

(1) 定义导出宏

在头文件中定义一个宏,用于控制 __declspec(dllexport)(编译 DLL 时)和 __declspec(dllimport)(使用 DLL 时):

cpp 复制代码
// MyDLL.h

#ifdef MYDLL_EXPORTS
    #define MYDLL_API __declspec(dllexport)  // 编译 DLL 时导出
#else
    #define MYDLL_API __declspec(dllimport)  // 使用 DLL 时导入
#endif

(2) 导出函数/类

在 DLL 项目中,使用 MYDLL_API 标记要导出的函数或类:

cpp 复制代码
// MyDLL.h
MYDLL_API int Add(int a, int b);  // 导出函数

class MYDLL_API MyClass {         // 导出类
public:
    MyClass();
    int Multiply(int a, int b);
};

(3) 实现 DLL 函数

cpp 复制代码
// MyDLL.cpp
#include "MyDLL.h"

int Add(int a, int b) {
    return a + b;
}

MyClass::MyClass() {}
int MyClass::Multiply(int a, int b) {
    return a * b;
}

(4) 编译生成 DLL

  • Visual Studio:

    • 右键项目 -> 属性 -> 配置类型 设为 "动态库(.dll)"。
    • 编译后生成 MyDLL.dll 和 MyDLL.lib(导入库)。
  • CMake:

    cmake 复制代码
    add_library(MyDLL SHARED MyDLL.cpp MyDLL.h)

2. 使用动态库

(1) 包含头文件

cpp 复制代码
#include "MyDLL.h"  // 确保头文件路径正确

(2) 链接导入库(.lib)

  • 方法 1:项目属性配置(推荐)

    • 右键项目 -> 属性 -> 链接器 -> 输入 -> 附加依赖项 ,添加 MyDLL.lib。
    • 链接器 -> 常规 -> 附加库目录 ,添加 .lib 所在路径。
  • 方法 2:#pragma comment(仅 MSVC)

    cpp 复制代码
    #pragma comment(lib, "MyDLL.lib")

(3) 运行时加载 DLL

确保 MyDLL.dll 位于:

  • 可执行文件(.exe)所在目录,或
  • 系统 PATH 环境变量包含的路径。

3. 动态加载(运行时显式加载)

如果不想静态链接 .lib,可以使用 LoadLibrary + GetProcAddress 动态加载:

cpp 复制代码
#include <windows.h>

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

int main() {
    HMODULE hDll = LoadLibrary(L"MyDLL.dll");
    if (!hDll) {
        std::cerr << "Failed to load DLL!" << std::endl;
        return 1;
    }

    // 获取函数指针
    AddFunc add = (AddFunc)GetProcAddress(hDll, "Add");
    if (!add) {
        std::cerr << "Failed to find function!" << std::endl;
        FreeLibrary(hDll);
        return 1;
    }

    int result = add(3, 4);  // 调用 DLL 函数
    std::cout << "Result: " << result << std::endl;

    FreeLibrary(hDll);  // 释放 DLL
    return 0;
}

4. 常见问题

(1) 无法解析的外部符号(LNK2019)

  • 原因 :未正确链接 .lib 或 __declspec(dllimport) 未正确应用。
  • 解决 :
    • 检查 MYDLL_API 是否正确定义。
    • 确保 .lib 路径正确。

(2) 找不到 DLL(运行时错误)

  • 原因 :DLL 不在 PATH 或 .exe 目录。
  • 解决 :
    • 将 DLL 复制到 .exe 所在目录。
    • 或修改 PATH 环境变量。

(3) 名称修饰(Name Mangling)问题

  • C++ 函数名会被编译器修饰 (如 ?Add@@YAHHH@Z),导致 GetProcAddress 失败。
  • 解决 :
    • 使用 extern "C" 避免修饰:

      cpp 复制代码
      extern "C" MYDLL_API int Add(int a, int b);
    • 或使用 .def 文件显式导出名称。


5. 跨平台兼容(Linux/macOS)

在 Linux/macOS 上,动态库是 .so(Shared Object)或 .dylib,使用 __attribute__((visibility("default"))) 导出:

cpp 复制代码
// MyDLL.h
#ifdef __GNUC__
    #define MYDLL_API __attribute__((visibility("default")))
#else
    #define MYDLL_API __declspec(dllexport)
#endif

编译:

bash 复制代码
g++ -shared -fPIC -o libMyDLL.so MyDLL.cpp

使用:

cpp 复制代码
#include <dlfcn.h>
void* handle = dlopen("libMyDLL.so", RTLD_LAZY);
auto add = (AddFunc)dlsym(handle, "Add");

总结

步骤 Windows (DLL) Linux/macOS (SO)
导出宏 __declspec(dllexport) __attribute__((visibility("default")))
导入宏 __declspec(dllimport) (通常不需要)
编译 cl /LD MyDLL.cpp g++ -shared -fPIC -o libMyDLL.so MyDLL.cpp
加载方式 LoadLibrary + GetProcAddress dlopen + dlsym

正确导出和使用动态库可以大幅提高代码的模块化和复用性。

相关推荐
aqiu1111111 小时前
【C++算法打怪专栏】8. 字符串转换整数 (atoi)
开发语言·c++·算法
爱吃香菜的初学者1 小时前
十四.Linux——消息队列
linux·运维·开发语言
迅猛龙办公室1 小时前
python实现倒序输出数字
开发语言·python
h39746 小时前
DirectShow过滤器开发-视频源过滤器
c++·windows·音视频·directshow
夏幻灵7 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码7 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
西飘客8 小时前
vs 怎么根据dll 生成lib文件
c++·qt
bkspiderx9 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
程序员老陆9 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光9 小时前
C语言入门,深入理解指针(3)
c语言·开发语言