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. eclipse的debug模式下启动不了tomcat

      使用eclipse启动tomcat,正常模式下可以启动tomcat,却在debug模式下无法启动tomcat. 这个问题可能是由于eclipse和tomcat的交互而产生的,在以debug模式启动to ...

    2. there was an error running the selected code generator unable to retrieve metadata for

      there was an error running the selected code generator unable to retrieve metadata for PROBLEM: I ha ...

    3. node-sass 安装失败 Failed at the node-sass@4.9.2 postinstall script的解决

      控制台运行npm install时报错,报错信息如下: npm ERR! code ELIFECYCLEnpm ERR! errno 1npm ERR! node-sass@4.9.2 postins ...

    4. AES和RSA加解密的Python用法

      AES AES 是一种对称加密算法,用key对一段text加密,则用同一个key对密文解密, from Crypto import Random from Crypto.Hash import SHA ...

    5. Laravel 深入理解路由和URL生成

      原文地址: Laravel 深入理解路由和URL生成 在模板中我们一般不会直接写死url,而是用url助手生成url,本文介绍一下url助手的使用以及遇到的一些比较头疼的问题. 首先,我们创建了一个路 ...

    6. Jquery EasyUI Combotree根据选中的值展开所有父节点

      Jquery EasyUI Combotree根据选中的值展开所有父节点  Jquery EasyUI Combotree 展开父节点, Jquery EasyUI Combotree根据子节点选中的 ...

    7. Android查看文件大小

      查看当前路径下的各个挂载模块的大小及剩余量(例如在根目录执行) df #输出 Filesystem Size Used Free Blksize /sys/fs/cgroup .0K /mnt/ase ...

    8. 关于ie浏览器信任站点的代码

      1检测用户当前浏览器是否将域名的ip添加信任站点 js代码 //域名ip的获取 var hostname = window.location.hostname;       var WshShell ...

    9. C#Web从0到1—创建一个web并从VS集成的SQLlocalDB数据库中查询数据

      软件说明: VS2017,腾讯云服务器10元1个月,系统Win2012 R2标准版 第一步:建立第一个网页 建立工程 建好后,可以打开View选项打开项目资源浏览器和工具箱,后文会多次用到这两个版面 ...

    10. Linux 命令 which whereis locate find

      which: 查询某指令的完整路径 $ which [-a] command -a: 将所有在PATH目录中可以找到的指令均列出. 注意:只搜索PATH下的路径. whereis: 只搜索几个特定目录 ...