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. Direct3D 11 Tutorial 3: Shaders and Effect System_Direct3D 11 教程3:着色器和效果系统

      概述 在上一个教程中,我们设置了一个顶点缓冲区并将一个三角形传递给GPU. 现在,我们将逐步完成图形管道并查看每个阶段的工作原理. 将解释着色器和效果系统的概念. 请注意,本教程与前一个源代码共享相同 ...

    2. 【深入Java虚拟机】一 JVM类加载过程

      首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时候进行类初始化? 3.什么时候会为变量分配内存? 4.什么时候会为变量赋默 ...

    3. 使用 pt-online-schema-change 实现在线DDL

      问题背景 平时进行修改表的结构,更改字段,新增字段,更改字段名称一般都是通过ALTER TABLE  语法进行修改的.对于小表或者并发访问不是很大的情况是OK.但是如果是在线大表,那就很麻烦.由于表数 ...

    4. python 中 __init__方法

      注意1,__init__并不相当于C#中的构造函数,执行它的时候,实例已构造出来了. class A(object): def __init__(self,name): self.name=name ...

    5. 关于linux - Centos 7 系统下使用PXE网络的方式(pxe+dhcpd+tftp+httpd)安装操作系统

      PXE(Pre-boot Execution Environment)是由Intel设计的协议,它可以使计算机通过网络而不是从本地硬盘.光驱等设备启动. 现代的网卡,一般都内嵌支持PXE的ROM芯片. ...

    6. OpenJDK和JDK区别

      OpenJDK和JDK区别 OpenJDK与JDK的区别分析 Sun的JDK7.OpenJDK及IcedTea释疑 简介(ps): 简单来说jdk从7开始,弄出一个可以自由使用的公共版本(openjd ...

    7. Less 编译生成 css

      开发模式下使用less.js <link rel="stylesheet/less" type="text/css" href="~/Conte ...

    8. kaggle竞赛-保险转化-homesite

      时间格式的转化 查看数据类型 查看DataFrame的详细信息 填充缺失值 category 数据类型转化 模型参数设定 结论 该项目是针对kaggle中的homesite进行的算法预测,使用xgbo ...

    9. oracle sqlplus命令详解

      涉及到的知识要点 a.带有一个&的替换变量的用法b.带有两个&的替换变量用法c.define命令用法d.accept命令用法e.定制SQL*Plus环境f.在glogin.sql文件中 ...

    10. 时时监控的rtsp流视频显示在前端与一些css;

      不过试了下只兼容IE. <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...