【C++】静态库与动态库调用

静态链接库的调用方法

静态链接库的调用涉及库的准备、项目配置和代码编写三个主要环节。下面详细介绍不同平台下的调用方式。

1. Windows平台调用静态库(.lib)

准备工作

  • 拥有静态库文件(mylib.lib)
  • 拥有对应的头文件(mylib.h)

方法一:通过VS项目设置

  1. 添加头文件路径
    项目属性 → C/C++ → 常规 → 附加包含目录
    
  2. 添加库目录
    项目属性 → 链接器 → 常规 → 附加库目录
    
  3. 指定库文件
    项目属性 → 链接器 → 输入 → 附加依赖项 → 添加"mylib.lib"
    

方法二:代码中直接指定

#pragma comment(lib, "mylib.lib")  // 自动链接库文件
#include "mylib.h"                 // 包含头文件

int main() {
    lib_function();  // 调用库函数
    return 0;
}

2. Linux/Unix平台调用静态库(.a)

准备工作

  • 静态库文件(libmylib.a)
  • 头文件(mylib.h)

编译命令

g++ main.cpp -I/path/to/headers -L/path/to/libs -lmylib -o myapp

参数说明:

  • -I:指定头文件目录
  • -L:指定库文件目录
  • -l:指定库名(去掉lib前缀和.a后缀)

完整示例

假设目录结构:

project/
├── include/
│   └── mylib.h
├── lib/
│   └── libmylib.a
└── src/
    └── main.cpp

编译命令:

g++ src/main.cpp -Iinclude -Llib -lmylib -o myapp

3. 跨平台通用方法(CMake)

CMakeLists.txt示例

cmake_minimum_required(VERSION 3.10)
project(MyApp)

# 设置头文件路径
include_directories(include)

# 添加静态库
add_library(mylib STATIC IMPORTED)
set_target_properties(mylib PROPERTIES
    IMPORTED_LOCATION "lib/libmylib.a"  # Windows用.lib路径
)

# 创建可执行文件
add_executable(myapp src/main.cpp)

# 链接静态库
target_link_libraries(myapp mylib)

4. 静态库调用注意事项

  1. 符号冲突

    • 当多个静态库包含相同符号时会导致链接错误
    • 解决方法:使用命名空间或重命名冲突符号
  2. 初始化顺序

    • 静态库中的全局对象构造函数调用顺序不确定
    • 解决方法:显式初始化或使用单例模式
  3. 库依赖顺序

    • 链接时库的顺序很重要,被依赖的库应放在后面
    • 例如:g++ main.o -lA -lB (A依赖B时)
  4. 调试信息

    • 发布版静态库通常去除了调试信息
    • 开发时可链接调试版库(通常带有d后缀,如mylibd.lib)
  5. C/C++混合调用

    #ifdef __cplusplus
    extern "C" {
    #endif
    // C函数声明
    #ifdef __cplusplus
    }
    #endif
    

5. 静态库调用示例代码

头文件(mylib.h)

#ifndef MYLIB_H
#define MYLIB_H

#ifdef __cplusplus
extern "C" {
#endif

void print_message(const char* msg);
int add_numbers(int a, int b);

#ifdef __cplusplus
}
#endif

#endif

主程序(main.cpp)

#include <iostream>
#include "mylib.h"

int main() {
    print_message("Hello from static library!");
    std::cout << "3 + 5 = " << add_numbers(3, 5) << std::endl;
    return 0;
}

动态链接库(DLL/SO)调用详解

动态链接库的调用分为显式调用和隐式调用两种主要方式,下面详细介绍各平台下的调用方法。

一、Windows平台动态库调用

1. 隐式调用(加载时链接)

特点

  • 需要.lib导入库和.dll文件
  • 程序启动时自动加载

步骤

  1. 准备文件

    • 头文件(mylib.h)
    • 导入库(mylib.lib)
    • 动态库(mylib.dll)
  2. 项目配置

    // 方法1:代码中指定
    #pragma comment(lib, "mylib.lib")
    
    // 方法2:项目属性设置
    // 链接器 → 输入 → 附加依赖项:mylib.lib
    
  3. 代码中使用

    #include "mylib.h"
    
    int main() {
        library_function();  // 直接调用
        return 0;
    }
    
  4. 部署要求

    • 需将.dll文件放在:
      • 应用程序目录
      • 系统目录
      • PATH环境变量包含的目录

2. 显式调用(运行时链接)

特点

  • 只需.dll文件
  • 可以动态加载/卸载

示例代码

#include <windows.h>
#include <iostream>

typedef void (*FuncPtr)(const char*);

int main() {
    HINSTANCE hDll = LoadLibrary(TEXT("mylib.dll"));
    if (!hDll) {
        std::cerr << "无法加载DLL" << std::endl;
        return 1;
    }

    FuncPtr func = (FuncPtr)GetProcAddress(hDll, "exported_function");
    if (func) {
        func("Hello from DLL!");
    } else {
        std::cerr << "找不到函数" << std::endl;
    }

    FreeLibrary(hDll);
    return 0;
}

二、Linux/Unix平台动态库调用

1. 隐式调用

编译命令

g++ main.cpp -Iinclude -Llib -lmylib -o myapp

运行前

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/libs
./myapp

2. 显式调用

示例代码

#include <dlfcn.h>
#include <iostream>

typedef void (*FuncPtr)(const char*);

int main() {
    void* handle = dlopen("libmylib.so", RTLD_LAZY);
    if (!handle) {
        std::cerr << dlerror() << std::endl;
        return 1;
    }

    FuncPtr func = (FuncPtr)dlsym(handle, "exported_function");
    if (func) {
        func("Hello from SO!");
    } else {
        std::cerr << dlerror() << std::endl;
    }

    dlclose(handle);
    return 0;
}

编译时

g++ main.cpp -ldl -o myapp

三、跨平台封装示例

#ifdef _WIN32
#include <windows.h>
#define LIB_HANDLE HINSTANCE
#define OPEN_LIB(name) LoadLibrary(TEXT(name))
#define GET_FUNC(handle, name) GetProcAddress(handle, name)
#define CLOSE_LIB(handle) FreeLibrary(handle)
#else
#include <dlfcn.h>
#define LIB_HANDLE void*
#define OPEN_LIB(name) dlopen(name, RTLD_LAZY)
#define GET_FUNC(handle, name) dlsym(handle, name)
#define CLOSE_LIB(handle) dlclose(handle)
#endif

int main() {
    LIB_HANDLE lib = OPEN_LIB("mylib");
    if (!lib) {
        #ifdef _WIN32
        std::cerr << "加载DLL失败" << std::endl;
        #else
        std::cerr << dlerror() << std::endl;
        #endif
        return 1;
    }

    auto func = (void(*)(const char*))GET_FUNC(lib, "exported_function");
    if (func) {
        func("Hello Cross-Platform!");
    }

    CLOSE_LIB(lib);
    return 0;
}

四、调用方式对比

特性隐式调用显式调用
加载时机程序启动时运行时按需加载
文件依赖需要.lib/.a导入库只需.dll/.so文件
性能启动稍慢启动快,但首次调用有延迟
灵活性高(可动态加载/卸载)
错误处理启动失败直接报错可运行时处理加载错误
适用场景核心依赖插件系统/可选功能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值