动态库与静态库的区别在windows及linux环境下的制作及用法

Posted 森明帮大于黑虎帮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态库与静态库的区别在windows及linux环境下的制作及用法相关的知识,希望对你有一定的参考价值。

文章目录

  • 静态库会被编译链接到到可执行程序中,使可执行程序变得臃肿,每次发布程序必须重新编译所有的程序。但程序运行时不需要依赖其他库。可单独直接运行。
  • 动态库不会被编译链接到可执行程序中,会与可执行程序一起存在,在可执行程序开始运行的时候,才会主动加载所需要的动态库。每次发布程序可根据实际需要只发布所需的动态库,而不必重新编译所有程序(该方法一般用于商用:省时省力)。

在linux 环境下:

  • 静态编译需要静态库(libxxx.a),静态编译成可执行程序后(一般程序会比较大),可单独运该程序,不需要依赖其他文件。

  • 动态编译需要动态库(libxxx.so),动态编译成可执行文件,需要与所需要的动态库一起存在,才可运行。

  • 静态库与动态库的制作可直接使用gun编译器

在windows环境下:

  • 静态编译需要静态库(xxx.lib),静态编译成可执行程序后(一般程序会比较大),可单独运该程序,不需要依赖其他文件。
  • 动态编译需要既需要动态库(xxx.dll)又需要静态库(xxx.lib),动态编译成可执行文件,需要与所需要的动态库(xxx.dll一起存在,才可运行。
  • 静态库与动态库的制作可直接使用Microsoft visual studio 编译器。

dll和lib简介

在Windows下很好理解这些概念,因为当你需要引入一个动态库(dll)或者一个静态库(lib)时一般的步骤是:

  • 添加头文件。
  • 配置头文件目录。
  • 配置库的目。
  • 将dll拷贝到可执行文件所在的目录(仅限于动态库)。

因此,就很好理解.h文件、.dll文件和.lib文件的关系:

  • .h文件是编译时需要的,因为里面有函数或变量声明。
  • .dll文件是生成的动态库,是在程序运行时动态加载的。
  • 而.lib文件就有话说了,首先,对于一个静态库来说,其是以xxx.lib的形式,而对于一个动态库来说,当IDE帮我们生成了.dll文件时,还会同时生成一个xxx.lib文件,这里的.lib不是静态库,而是动态链接库的导入库(Import Libary)。

Windows下使用静态库

生成静态库。

在VS2013中创建Win32项目,创建后编译器弹出选项框,选择静态库项目

分别编写.h文件和.cpp文件

//StaticMath.h
#pragma once
class StaticMath

public:
    StaticMath(void);
    ~StaticMath(void);
    static double add(double a, double b);
    static double sub(double a, double b);
    static double mul(double a, double b);
    static double div(double a, double b);
;

//StaticMath.cpp
#include "StaticMath.h"
double StaticMath::add(double a, double b)

    return a + b;


右键项目->生成

在项目的Debug目录下生成静态库。

使用静态库:

创建控制台应用程序,并编写测试代码:**

//testStatic.cpp
#include <iostream>
#include "StaticMath.h"
int main()

    double a = 1.2;
    double b = 2.4;
    std::cout << "a+b="<<StaticMath::add(a, b)<<std::endl;
    system("pause");
    return 0;

配置项目

配置头文件引用目录:项目属性->C/C+±>常规->附加包含目录->静态库头文件所在的目录。

配置静态库的目录:项目属性->链接器->命令行->其它选项->添加静态库的绝对路径。

测试静态库

直接编译运行测试项目,结果如下:

Windows下使用动态库

Windows下使用动态库就要比静态库复杂多了。

创建动态库

在VS2013创建Win32项目,并选择动态库,这时系统会自动帮我们做一些事情:比如会写DLLMain函数作为初始化的入口、比如会初始化.h和.cpp文件,里面有示例导出函数和导出类声明。我们只需要在其基础上做一些补充即可

//DynamicMath.h
// 下列 ifdef 块是创建使从 DLL 导出更简单的宏的标准方法。
// 此 DLL 中的所有文件都是用命令行上定义的 DYNAMICMATH_EXPORTS
// 符号编译的。在使用此 DLL 的任何其他项目上不应定义此符号。
// 这样,源文件中包含此文件的任何其他项目都会将 DYNAMICMATH_API
// 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的符号视为是被导出的。

#ifdef DYNAMICMATH_EXPORTS
#define DYNAMICMATH_API __declspec(dllexport)
#else
#define DYNAMICMATH_API __declspec(dllimport)
#endif

// 此类是从 DynamicMath.dll 导出的
class DYNAMICMATH_API CDynamicMath 
public:
    CDynamicMath(void);

    // TODO:  在此添加您的方法。
    static double add(double a, double b);
    static double sub(double a, double b);
    static double mul(double a, double b);
    static double div(double a, double b);
;
//示例导出变量声明
extern DYNAMICMATH_API int nDynamicMath;
//示例导出函数声明
DYNAMICMATH_API int fnDynamicMath(void);

这里编译器生成的模板中,CDynamicMath类已经被DYNAMICMATH_API(从DynamicMath.dll导出)修饰,因此类中的成员函数无需再用DYNAMICMATH_API修饰。

// DynamicMath.cpp : 定义 DLL 应用程序的导出函数。

#include "stdafx.h"
#include "DynamicMath.h"


// 这是导出变量的一个示例
DYNAMICMATH_API int nDynamicMath=0;

// 这是导出函数的一个示例。
DYNAMICMATH_API int fnDynamicMath(void)

    return 42;


// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 DynamicMath.h
CDynamicMath::CDynamicMath()

    return;


//我自己添加的导出函数
double CDynamicMath::add(double a, double b)

    return a + b;

右键项目->生成将在debug目录下将生成

DynamicMath.dll(动态链接库)
DynamicMath.lib(动态链接库的导入库)


有了.h文件 、动态链接库、导入库这三件套,我们就可以很容易的静态加载(即隐式链接的方式)动态链接库了。否则的话,就需要自己LoadLibrary调入DLL文件,再手动GetProcAddress获得对应函数了(又称显式链接)。

有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。

一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。在动态库的情况下,有两个文件,而一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。

使用动态库

这里使用隐式链接(静态加载)的方式。

创建控制台应用程序,并编写测试代码

#include "DynamicMath.h"
#include <iostream>
int main()

    int num = fnDynamicMath();//自动生成的示例导出函数
    std::cout << num << std::endl;
    double a=1.2;
    double b=2.5    ;
    std::cout << CDynamicMath::add(a, b) << std::endl;
    system("pause");
    return 0;

配置项目

配置头文件目录:项目属性->C/C+±>常规->附加包含目录。

配置导入库(附加依赖项)目录:项目属性->链接器->常规->附加库目录
除此之外还需要配置具体附加依赖项.lib:配置属性->链接器->输入-> 在“附加依赖项”里添加“DynamicMath.lib”。



配置动态链接库目录:项目属性->配置属性->VC++目录->库目录。

测试

编译运行测试动态库项目,发现错误:说系统找不到DynamicMath.dll文件,事实上,我们需要将dll文件拷贝到测试工程的Debug目录下后正常运行:

以上是关于动态库与静态库的区别在windows及linux环境下的制作及用法的主要内容,如果未能解决你的问题,请参考以下文章

静态链接库与动态链接库的区别及动态库的创建(转)

请教关于linux中静态库与动态库的问题

深入探讨Linux静态库与动态库的详解(转)

[Linux 高并发服务器]制作静态库与动态库

动态链接库与静态链接库的区别

动态库与静态库的区别