Windows下静态库与动态库的创建与使用

学习内容:本博客介绍了Windows下使用Visual C++ 6.0制作与使用静态库与动态库的方法。

————————CONTENTS————————


一.什么是静态库与动态库?

库(Library)是可以复用的代码,在一些大型项目中常常会用到库。

本质上说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

在前期的课程中,我们学习了Linux下静态库与动态库的使用,Windows下与之对应:

  • 静态库:linux下.a文件、windows下.lib文件
  • 动态库:linux下.so文件、windows下.dll文件

所谓静态、动态是指链接。回顾一下将一个程序编译成可执行文件的步骤:

静态库与动态库的区别就在于,【链接阶段】如何处理库,从而连接成可执行程序。

1.静态库

之所以成为【静态库】,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。

静态库的特点可总结为:

  1. 静态库对函数库的链接是放在编译时期完成的。
  2. 程序在运行时与函数库再无瓜葛,移植方便。
  3. 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

Linux下使用ar工具、Windows下使用lib.exe,将目标文件压缩到一起,并且对其进行编号和索引,以便于查找和检索。一般创建静态库的步骤如图所示:

2.动态库

通过上面的介绍发现静态库,容易使用和理解,也达到了代码复用的目的,那为什么还需要动态库呢?

为什么需要动态库,其实也是静态库的特点导致。

  • 空间浪费是静态库的一个问题。

  • 另一个问题是静态库会对程序的更新、部署和发布带来麻烦。如果静态库lib.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新

动态库特点总结如下:

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

综上所述,静态库与动态库的不同点在于:代码被载入的时刻不同

  • 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大
  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小
  • 动态库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

返回目录


二.静态库的创建与使用

1.静态库的创建

1.我们先来完成准备工作。打开Visual C++ 6.0,点击左上角/File->New...,选择需要新建的对象:

选择Workspaces选项卡,输入Workspaces name以及Location,新建一个工作区:

本篇博客所用到的Project都建在这个工作区就可以啦~

2.选中我们新建的workspace,右击选择Add New Project to Workspace...

我们先尝试创建静态库,因此在Project选项卡选择Win32 Static Library,并在右侧输入Project name即可完成项目创建。

接下来一路next,一个Win32 Static Library格式的Project就建成了:

3.注意到一个工程下面有两个文件夹,分别是Source FilesHeader Files。顾名思义,Source Files用来存放源文件,如.cpp等;Header Files则用来存放头文件。

我们先来建一个头文件,存放函数说明。

选中Header Files文件夹,点击File->New...->Files->C/C++ Header File,并输入文件名,完成创建。

内容为:

int statlib_demo(int a, int b);

4.同样的方法,在Source Files中新建staticlib.cpp,这次需要选中C++ Source File

内容为:

#include "staticlib.h"
int statlib_demo(int a, int b)
{
if (a > b)
return a-b;
else
return a+b;
}

就此完成了代码基本的编写。

5.选择这个Project,依次点击CompileBuild按钮:

打开Project所在文件夹中的Debug文件夹,可以看到成功生成lib.lib,这就是我们需要的静态库啦~

返回目录

2.静态库的使用

接下来我们编写代码,对生成的静态库进行测试。

1.与前面类似,这次在workspace中新建一个Win32 Console Application的Project:

选择A "Hello, world!" application.

可以看到在工作区生成了一个名为libTest的Project,其中包含一些自动生成的文件和代码:

2.将刚才生成的lib.lib拷贝到新建的这个项目文件夹下,以进行后续的调用。

3.修改这个Project中的代码,完成对静态库调用的测试:

libTest.cpp

#include "stdafx.h"
#include "../lib/staticlib.h" //要注意在这里添加头文件的位置
int main(int argc, char* argv[])
{
printf("Hello World!\n");
int iRet;
iRet = statlib_demo(3,5);
printf("the result of value is %x\n",iRet);
return 0;
}

StdAfx.h:只需要在#include <stdio.h>下一行加上#pragma comment (lib,"lib")即可。其中,第一个“lib”代表链接一个lib库,第二个“lib”是这个库的名字,需根据实际情况修改。

StdAfx.cpp不需要做改动。

4.完成了以上代码的编写和修改,Build这个项目,并Execute Program就可以了。运行结果如下:

到此为止,我们完成了静态库的编写和测试。最关键的点就是#pragma comment(lib,"XXX") 这句预处理指令了。

静态链接时,编译器将函数和过程都编译到exe文件,且函数的相对位置在链接时已经确定。多个程序调用同一个函数时,内存中保存多份函数。

返回目录


三.动态库的创建与使用

1.动态库的创建

DLL(Dynamic Linkable Library),动态链接库,可以向程序提供一些函数、变量或类。这些可以直接拿来使用。

DLL中一般定义有两种类型的函数:导出函数和内部函数。其中:

  • 导出函数可以被外部程序调用;
  • 内部函数只能在DLL内部使用。

为了使生成的dll文件可以被外部程序调用,我们主要关注导出函数的生成与使用。

从dll中声明导出函数有两种方式:

  • (1)用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息;
  • (2) 用__declspec(dllexport)来声明函数

下面我们来详细了解这两种方式的用法。

一、使用.def文件

1.同样地,在workspace新建一个Project,选择为Win32 Dynamic-Link Library

选择A simple DLL project.

可以看到在工作区生成了一个名为dll_def的Project,其中包含一些自动生成的文件和代码:

2.修改这个Project中的代码,完成动态库的编写:

dll_def.cpp

#include "stdafx.h"
#include "dll_def.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
} int cmp3_demo(int a, int b)
{
if (a > b)
return a;
else
return b;
}

Header Files中新建一个dll_def.h,内容为:

int cmp3_demo(int a, int b);

其他已存在的文件不需要做修改。

3.最关键的步骤到了!!!——编写.def文件。

  • DEF文件是一个包含EXE文件或DLL文件声明的文本文件;
  • 每个.DEF文件至少必须包含LIBRARY语句和EXPORTS语句

.def文件的规则为:

  1. LIBRARY语句说明.def文件相应的DLL;
  2. EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用);
  3. .def 文件中的注释由每个注释行开始处的分号 (

    Windows下静态库与动态库的创建与使用的更多相关文章

    1. C++ 静态库与动态库以及在 Windows上 的创建、使用

      一.什么是库 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可以 ...

    2. 【C/C++开发】C++静态库与动态库以及在Linux和Windows上的创建使用

      原文出处: 吴秦的博客    这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学 ...

    3. C++ 系列:静态库与动态库

      转载自http://www.cnblogs.com/skynet/p/3372855.html 这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择 ...

    4. C++静态库与动态库

      C++静态库与动态库 这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学,推荐一 ...

    5. (转)C++静态库与动态库

      转自:http://www.cnblogs.com/skynet/p/3372855.html C++静态库与动态库 这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别, ...

    6. (转)C++静态库与动态库

      本文出自 http://www.cnblogs.com/skynet/p/3372855.html 吴秦 什么是库 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不 ...

    7. 【转】C++静态库与动态库

      C++静态库与动态库 这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学,推荐一 ...

    8. C++静态库与动态库(比较透彻)

      这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学,推荐一本书<程序员的自 ...

    9. C++静态库与动态库详解

      1 库的概念? 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库. 2 动态库与静态库的概念? 先回顾一下编译过程: 2.1 静态库 静态库在链接阶段,会将汇编生成的目 ...

    10. C++静态库与动态库深入研究

      什么是库 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可以被操 ...

    随机推荐

    1. Datagrip连接SQLServer Connecting DataGrip to MS SQL Server

      Connecting DataGrip to MS SQL Server Posted on June 21, 2016 by Maksim Sobolevskiy Some specific nee ...

    2. pyCharm最新激活码(2018激活码)

      首先输入新的License sever address 首先尝试处理方法是,针对过期会弹出激活框: 选择 Activate new license with License server (用lice ...

    3. 美客分销商城-接力购源码系统,全开源代码可进行二次开发,微信小程序分销商城

      1. 准备服务器.域名(SSL证书).认证的微信小程序.微信支付商户号 2. 系统功能简介 三.演示案例,微信扫码查看 四.后台管理系统 五. 全套开源源码,进行二次开发 六.本系统完美运营,全套代码 ...

    4. tensorflow 调试tfdbg

      1.执行pip install pyreadline 安装pyreadline 2.修改对应代码如下 with tf.Session() as sess: sess.run(tf.global_var ...

    5. CentOS6.5 添加开机自启动脚本

      有时候我们需要Linux系统在开机的时候自动加载某些脚本或系统服务.在解问题之前先来看看Linux的启动流程. 一.Linux的启动流程 主要顺序就是: 1. 加载内核 2. 启动初始化进程 3. 确 ...

    6. 异常:Project configuration is not up-to-date with pom.xml 解决方案

      错误描述,在导入Maven项目后出现下面错误: Description Resource Path Location Type Project configuration is not up-to-d ...

    7. 【Py-Github】根据条件筛选Github repo的例子

      条件: language:python commits:>100 contributors:>2 stars:>5 fork:0 实现: from github import Git ...

    8. 四、Sql Server 基础培训《进度4-插入数据(实际操作)》

      知识点: 假设有订单表 CREATE TABLE Order ( ID int identity(1,1) not null primary key, --内码 BillNo varchar(100) ...

    9. linux 安装配置nexus以及maven私服应用

      ---------------------nexus---------------------- 1.编辑nexus脚本, 配置 RUN_AS_USER 参数vi /usr/local/src/nex ...

    10. python 接口自动化测试(六)使用unittest 批量用例管理

      我们日常项目中的接口测试案例肯定不止一个,当案例越来越多时我们如何管理这些批量案例?如何保证案例不重复?如果案例非常多(成百上千,甚至更多)时如何保证案例执行的效率?如何做(批量)测试数据的管理?如何 ...