天天看点

再谈静态库和动态库(C++)

文章目录

      • 说明
      • 动态库和静态库联系与区别
      • 静态库(static lib)注意事项
      • 动态库(dynamic lib + dll)注意事项
      • 常见问题
      • 联系博主

说明

  • 本文是在综合CSDN博客的基础上,再加上博主自己实践总结所写
  • 博主之前曾写过一篇博文介绍该内容,但那篇文章有囫囵吞枣之意,所以“再谈”
  • 本文若有错误之处,请在评论留言,及时回复
  • 本文涉及到的环境均为 Windows 10 + VS 2013

动态库和静态库联系与区别

  • 这是博主之前写的一篇入门文章,可以结合的看
VS下静态库与动态库的生成与使用
  • 其它相关文章,博主推荐
static lib和dynamic lib
VS2013动态库文件的创建及其使用详解
c++导出库

静态库(static lib)注意事项

  • 新建静态库工程
    • 正常写 .h 和 .cpp
  • 新建测试工程
    • 编辑 test.cpp
    • 将 .lib 复制到 test.cpp
    • 【属性 - 链接器 - 附加依赖项】加入 .lib 名称
    • 编译运行

动态库(dynamic lib + dll)注意事项

  • 新建动态库生成工程 DLLGenerater
    • 选择 控制台应用程序,其它请读者自行尝试,大同小异
    • 选择 DLL
    • 勾选 空项目
    • 预编译头VS 默认强制勾选
    • 安全开发生命周期(SDL)检查 选不选择无所谓
  • 新建若干 .h 和 .cpp,每个 .h 又可包括若干内容
    • math.h 和 math.cpp 示例代码(见文末所附代码)
    • animal.h 和 animal.cpp 示例代码(见文末所附代码)
  • 不写 main 函数
    • 如果想验证代码的正确性,可在属性将默认类型的配置类型像彗星修改为**.exe**进行编译运行
    • 编译即可,在 …/Debug 或者 …/Release 目录下生成 DLLGenerater.lib 和 DLLGenerater.dll
  • 新建测试动态库工程 DLLUser
    • 新建 test.cpp
    • 复制 math.h 和 animal.h 到 test.cpp 同一级目录
    • 复制 DLLGenerater.lib 和 DLLGenerater.dll 也到 test.cpp 同一级目录
    • DLLUser 属性的链接器的附加依赖项中添加 DLLGenerater.lib
    • 编辑 test.cpp 的内容(见文末所附代码)
    • 编译运行成功
  • 附:使用 DLLGenerater.dll 的几种方式
    • 编译运行时候
      • 第一种方式
        • .h、.lib、.dll、随 test.cpp 同一级目录
      • 第二种方式
        • .h、.lib 随 test.cpp 同一级目录
        • 系统环境变量的 system 的 path 加入 .dll 的路径(Windows 下可能需要重启电脑)
      • 第三种方式
        • .h 随 test.cpp 同一级目录
        • test.cpp 中加入

          #pragma comment(lib,"DLLGenerater.lib")

        • 系统环境变量的 system 的 path 加入 .dll 的路径(Windows 下可能需要重启电脑)
      • 第四种方式(类似于配置第三方库)
        • 【项目属性 - VC++目录 - 包含路径】 添加 .h 路径
        • 【项目属性 - VC++目录 - 包含库目录】 添加 .lib 路径
        • 【项目属性 - 链接器 - 附加依赖项】 写入具体的 .lib 名称
        • 系统环境变量的 system 的 path 加入 .dll 的路径(Windows 下可能需要重启电脑)
    • 脱离VS运行时候
      • 第一种方式
        • 将 .dll 和 .exe 放在一起
      • 第二种方式(这个是我猜测的,未经实际验证)
        • 预先就在文件中写入 .dll 的相对路径,这样的话可以在程序打包发布时候将 .dll 放入指定文件夹,具体可参见现有软件的安装程序(如参看 QQ 的安装程序路径)
  • 附:上述所提及代码

math.h

#ifndef _MATH_H_
#define _MATH_H_

#include <cmath> // 记得加头文件

// 有时候觉得写得麻烦
// 那么可以 typadef
#ifndef MY_DLL // 条件编译
#define MATH_EXPORT __declspec(dllexport)
#endif

// 对于函数(全局函数,成员函数等)
// __declspec(dllexport) 写在最前面
// 然后是返回值,函数名,形参
__declspec(dllexport) int add(int a, int b);

// 对于类,如果要导出所有函数
// 那么 __declspec(dllexport) 写在 class 和 类名中间
class __declspec(dllexport) ExportAllDll {
public:

    float getSin(float theta); // 普通成员函数
    static void printClass(); // 静态函数

private:

    const double PI = std::acos(-1);

    // 私有函数,不会导出!!!并且该导出无实际意义
    float __getTan(float theta);

};

// 对于类,如果要导出部分函数
// 则类名前不加 __declspec(dllexport)
// 而是在要导出的函数前面加上 __declspec(dllexport)
class ExportPartDll {
public:

    __declspec(dllexport) float getSqrt(float num); // 导出
    float getAbs(float num); // 不导出
};

// 也可以这样导出函数
MATH_EXPORT void getMatrix();

#endif // _MATH_H_
           

math.cpp

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

// .cpp 实现文件一概不写 __declspec(dllexport)
int add(int a, int b){
	return a + b;
}

// 类函数的实现记得加上类名
float ExportAllDll::getSin(float theta){
	return std::sinf(theta * PI / 180);
}

// 这里不写 static
void ExportAllDll::printClass(){
	std::cout << "printClass\n";
}

// 私有函数的实现
float __getTan(float theta){
	return 90.0f;
}

// 这个是要导出的函数
float ExportPartDll::getSqrt(float num){
	return std::sqrt(num);
}

// 这个不导出
float ExportPartDll::getAbs(float num){
	return std::abs(num);
}

// typedef __declspec(dllexport) MY_DLL 的使用
void getMatrix(){
	std::cout << "This is matrix.\n";
}
           

animal.h

#ifndef _ANIMAL_H_
#define _ANIMAL_H_

__declspec(dllexport) void printZoo();

#endif // _ANIMAL_H_
           

main.cpp

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

void printZoo(){
	std::cout << "printZoo()\n";
}
           

test.cpp

#include "math.h"
#include "animal.h"
#include <iostream>

int main(){

	// 测试全局函数
	int a = 1, b = 2;
	std::cout << add(a, b) << std::endl;

	// 测试导出类
	ExportAllDll ad;
	std::cout << ad.getSin(30) <<std::endl;
	ExportAllDll::printClass();

	// 测试类导出函数
	ExportPartDll pd;
	std::cout << pd.getSqrt(9.0f) << std::endl;
	// std::cout << pd.getAbs(-6.6f) << std::endl;

	// 测试全局函数
	getMatrix();

	// 测试全局函数
	printZoo();

	return 0;
}
           

常见问题

C++ dll库只生成dll文件,而未生成lib文件的问题
Error LNK2001 无法解析的外部符号 的几种情况及解决办法

联系博主

评论会尽快回复