C++静态和动态链接库导出和使用

1、简介

代码开发过程中会遇到很多已有的函数库,这些函数库是现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态链接库和动态链接库。

动态链接库包含了函数所在的DLL文件和函数入口等相关信息,代码由运行时加载在进程空间中的DLL提供,显示调用不需要仅需要动态链接库的dll文件,无需头文件.h和动态链接库.lib文件,隐式调用则需要上述三种文件。
动态库特点:

  • 动态库把对一些库函数的链接载入推迟到程序运行时期。
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 将一些程序升级变得简单。
  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)

静态链接库包含了函数实现本身,在编译的时候直接将代码放入程序中。在调用静态链接库的时,需要使用静态链接库的头文件.h以及静态链接库的.lib文件。

静态库特点:

  • 静态库对函数库的链接是放在编译时期完成的
  • 程序在运行时与函数库再无瓜葛,移植方便。
  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件
  • 如果静态库进行更新则应用该库的所有程序都需要重新编译(全量更新)。

2、Windows动态链接库使用

2.1 动态链接库生成

首先新建工程MathLibrary_dll,在源文件中添加MathLibrary.cpp,在头文件中添加MathLibrary.h,具体代码如下:

  • 添加头文件MathLibrary.h如下:
#pragma once

#ifndef MATHLIBRARY
#define MATHLIBRARY

#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dellexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif // MATHLIBRARY_EXPORTS


namespace MathLibrary {

	class MATHLIBRARY_API Arithmetic
	{
	public:
		Arithmetic();
		~Arithmetic();
		// Returns a + b
		double Add(double a, double b);

		// Returns a - b
		double Subtract(double a, double b);

		// Returns a * b
		double Multiply(double a, double b);

		// Returns a / b
		double Divide(double a, double b);

	private:

	};
	extern "C" MATHLIBRARY_API double power(double a, double ratio);
}
#endif // !MATHLIBRARY
  • 添加源文件MathLibrary.cpp
// MathLibrary.cpp
// compile with: cl /c /EHsc MathLibrary.cpp
// post-build command: lib MathLibrary.obj

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

namespace MathLibrary
{
    Arithmetic::~Arithmetic() {};
    Arithmetic::Arithmetic() {};

    double Arithmetic::Add(double a, double b)
    {
        return a + b;
    }

    double Arithmetic::Subtract(double a, double b)
    {
        return a - b;
    }

    double Arithmetic::Multiply(double a, double b)
    {
        return a * b;
    }

    double Arithmetic::Divide(double a, double b)
    {
        return a / b;
    }
    double power(double a, double ratio) {
        return pow(a, ratio);
    }
}
  • 生成动态链接库
    在项目的配置属性页选择配置类型为动态库(.dll)
    在这里插入图片描述
    生成的DLL文件如下所示:
    在这里插入图片描述

2.2 动态链接库使用

  • 新建测试动态链接库的项目MathLibrary_dll_test,并在源文件中添加一个测试代码如下所示:
#include <iostream>
#include "MathLibrary.h"
using namespace MathLibrary;

int main()
{
    double a = 7.0;
    int b = 99;
    double ratio = 2.0;
    Arithmetic *demo_class = new Arithmetic();
    std::cout <<"Add结果为= " << demo_class->Add(a, b) << std::endl;
    std::cout << "Multiply结果为= " << demo_class->Multiply(a, b) << std::endl;
    std::cout << "Divide结果为= " << demo_class->Divide(a, b) << std::endl;
    std::cout << "Subtract结果为= " << demo_class->Subtract(a, b) << std::endl;
    std::cout << "power结果为= " << power(a,ratio) << std::endl;
    delete demo_class;
    return 0;
}
  • 环境配置包括三步

1、属性页->C\C+±>附加包含目录,添加头文件目录
在这里插入图片描述
2、属性页->链接器->附加库目录中,添加lib文件目录
在这里插入图片描述
3、属性页->链接器->输入->附加依赖项,添加MathLibrary_dll.lib
在这里插入图片描述

  • 运行测试程序,结果正常显示如下:
    在这里插入图片描述

3、Windows静态链接库使用

3.1 静态链接库生成

首先新建工程MathLibrary,在源文件中添加MathLibrary.cpp,在头文件中添加MathLibrary.h,具体代码如下:

  • 添加头文件MathLibrary.h如下:
#pragma once

namespace MathLibrary {

	class Arithmetic
	{
	public:
		Arithmetic();
		~Arithmetic();
		// Returns a + b
		static double Add(double a, double b);

		// Returns a - b
		static double Subtract(double a, double b);

		// Returns a * b
		static double Multiply(double a, double b);

		// Returns a / b
		static double Divide(double a, double b);

	private:

	};
}
  • 添加源文件MathLibrary.cpp
#include "MathLibrary.h"

namespace MathLibrary
{
    Arithmetic::~Arithmetic() {};
    Arithmetic::Arithmetic() {};

    double Arithmetic::Add(double a, double b)
    {
        return a + b;
    }

    double Arithmetic::Subtract(double a, double b)
    {
        return a - b;
    }

    double Arithmetic::Multiply(double a, double b)
    {
        return a * b;
    }

    double Arithmetic::Divide(double a, double b)
    {
        return a / b;
    }
}
  • 设置属性页并生成静态链接库
    在这里插入图片描述
    生成的静态lib文件如下所示:
    在这里插入图片描述

3.2 静态链接库使用

  • 新建测试静态链接库的项目MathLibrary_test,并在源文件中添加一个测试代码test.cpp如下所示:
#include <iostream>
#include "MathLibrary.h"

int main()
{
    double a = 7.4;
    int b = 99;

    std::cout << "a + b = " <<
        MathLibrary::Arithmetic::Add(a, b) << std::endl;
    std::cout << "a - b = " <<
        MathLibrary::Arithmetic::Subtract(a, b) << std::endl;
    std::cout << "a * b = " <<
        MathLibrary::Arithmetic::Multiply(a, b) << std::endl;
    std::cout << "a / b = " <<
        MathLibrary::Arithmetic::Divide(a, b) << std::endl;

    return 0;
}
  • 环境配置
    在属性页->VC++目录->包含目录,添加头文件地址
    在属性页->VC++目录->库目录,添加库文件地址
    在这里插入图片描述
    在属性页->链接器->输入->附加依赖项,添加静态库lib名称MathLibrary.lib
    在这里插入图片描述
  • 运行测试程序,结果正常显示如下:
    在这里插入图片描述
    以上就是windows系统上使用visual studio 2019进行静态库和动态库的生成和使用说明,仅作记录。

参考:
https://blog.csdn.net/htt789/article/details/81454832
https://www.cnblogs.com/skynet/p/3372855.html
https://learn.microsoft.com/zh-cn/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170
——END——

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
文中是linux下 C++动态库 实现接口提供类导出的一个例子 注意其中使用函数返回基类指针的用法,因为Linux的动态链接库不能像MFC中那样直接导出类 一、介绍 如何使用dlopen API动态地加载C++函数和类,是Unix C++程序员经常碰到的问题。 事实上,情况偶尔有些复杂,需要一些解释。这正是写这篇mini HOWTO的缘由。 理解这篇文档的前提是对C/C++语言中dlopen API有基本的了解。 这篇HOWTO的维护链接是: http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ 二、问题所在 有时你想在运行时加载一个库(并使用其中的函数),这在你为你的程序写一些插件或模块架构的时候经常发生。 在C语言中,加载一个库轻而易举(调用dlopen、dlsym和dlclose就够了),但对C++来说,情况稍微复杂。 动态加载一个C++库的困难一部分是因为C++的name mangling (译者注:也有人把它翻译为“名字毁坏”,我觉得还是不翻译好), 另一部分是因为dlopen API是用C语言实现的,因而没有提供一个合适的方式来装载类。 在解释如何装载C++库之前,最好再详细了解一下name mangling。 我推荐您了解一下它,即使您对它不感兴趣。因为这有助于您理解问题是如何产生的,如何才能解决它们。 1. Name Mangling 在每个C++程序(或库、目标文件)中, 所有非静态(non-static)函数在二进制文件中都是以“符号(symbol)”形式出现的。 这些符号都是唯一的字符串,从而把各个函数在程序、库、目标文件中区分开来。 在C中,符号名正是函数名:strcpy函数的符号名就是“strcpy”,等等。 这可能是因为两个非静态函数的名字一定各不相同的缘故。 而C++允许重载(不同的函数有相同的名字但不同的参数), 并且有很多C所没有的特性──比如类、成员函数、异常说明──几乎不可能直接用函数名作符号名。 为了解决这个问题,C++采用了所谓的name mangling。它把函数名和一些信息(如参数数量和大小)杂糅在一起, 改造成奇形怪状,只有编译器才懂的符号名。 例如,被mangle后的foo可能看起来像foo@4%6^,或者,符号名里头甚至不包括“foo”。 其中一个问题是,C++标准(目前是[ISO14882])并没有定义名字必须如何被mangle, 所以每个编译器都按自己的方式来进行name mangling。 有些编译器甚至在不同版本间更换mangling算法(尤其是g++ 2.x和3.x)。 即使您搞清楚了您的编译器到底怎么进行mangling的,从而可以用dlsym调用函数了, 但可能仅仅限于您手头的这个编译器而已,而无法在下一版编译器下工作。 三、类 使用dlopen API的另一个问题是,它只支持加载函数。 但在C++中,您可能要用到库中的一个类,而这需要创建该类的一个实例,这不容易做到。 四、解决方案 1. extern "C" C++有个特定的关键字用来声明采用C binding的函数: extern "C" 。 用 extern "C"声明的函数将使用函数名作符号名,就像C函数一样。 因此,只有非成员函数才能被声明为extern "C",并且不能被重载。 尽管限制多多,extern "C"函数还是非常有用,因为它们可以象C函数一样被dlopen动态加载。 冠以extern "C"限定符后,并不意味着函数中无法使用C++代码了, 相反,它仍然是一个完全的C++函数,可以使用任何C++特性和各种类型的参数。
动态库和静态库编写方式基本相同,只是在编译链接时需要采用不同的方式。以下是C++动态库和静态库编写方法: ### 静态库 1. 创建静态库项目:打开Visual Studio,选择“新建项目”,然后选择“Win32控制台应用程序”,输入项目名称和路径,点击“确定”按钮。在弹出的窗口中选择“静态库”类型,然后点击“下一步”按钮,最后点击“完成”按钮。 2. 编写库文件代码:在项目中添加源文件,编写库文件的代码,并在头文件中声明需要导出的函数和类。 3. 生成静态库文件:在编译链接时将代码编译成静态库文件,可以手动编译或在Visual Studio中配置。在Visual Studio中,可以选择“生成”菜单中的“生成解决方案”或“生成项目”命令生成静态库文件。生成的静态库文件通常以.lib为扩展名。 4. 使用静态库:在使用静态库的应用程序中,需要在编译链接时将静态库文件链接到可执行文件中。可以在应用程序的项目属性中配置链接选项,将静态库文件添加到链接器的附加依赖项中。在代码中包含头文件即可使用静态库中的函数和类。 ### 动态库 1. 创建动态库项目:打开Visual Studio,选择“新建项目”,然后选择“Win32控制台应用程序”,输入项目名称和路径,点击“确定”按钮。在弹出的窗口中选择“动态链接库(DLL)”类型,然后点击“下一步”按钮,最后点击“完成”按钮。 2. 编写库文件代码:在项目中添加源文件,编写库文件的代码,并在头文件中声明需要导出的函数和类。需要使用__declspec(dllexport)关键字将需要导出的函数或类标记为可导出。 3. 生成动态库文件:在编译链接时将代码编译成动态库文件,可以手动编译或在Visual Studio中配置。在Visual Studio中,可以选择“生成”菜单中的“生成解决方案”或“生成项目”命令生成动态库文件。生成的动态库文件通常以.dll为扩展名。 4. 使用动态库:在使用动态库的应用程序中,需要在运行时加载动态库文件,并使用GetProcAddress函数获取动态库中需要使用的函数或类。在代码中包含头文件即可使用动态库中的函数和类。在编译链接时需要指定动态库文件的路径和名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI小花猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值