这里写目录标题
- 创建动态库
- 创建静态库
- 动态库与静态库的区别
- 动态链接与静态链接的区别
- 动态库的加载过程
- dll的创建以及应用程序隐式链接到dll的过程
- dll的创建以及应用程序显示链接到dll的过程
- 动态库的二进制兼容性
创建动态库
1.【新建】-》【项目】-》【动态链接库】
新建的动态库结构如下:
新建项目:MathLibrary.h
// MathLibrary.h - Contains declarations of math functions
#pragma once
#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif
// The Fibonacci recurrence relation describes a sequence F
// where F(n) is { n = 0, a
// { n = 1, b
// { n > 1, F(n-2) + F(n-1)
// for some initial integral values a and b.
// If the sequence is initialized F(0) = 1, F(1) = 1,
// then this relation produces the well-known Fibonacci
// sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
extern "C" MATHLIBRARY_API void fibonacci_init(
const unsigned long long a, const unsigned long long b);
// Produce the next value in the sequence.
// Returns true on success and updates current value and index;
// false on overflow, leaves current value and index unchanged.
extern "C" MATHLIBRARY_API bool fibonacci_next();
// Get the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();
// Get the position of the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned fibonacci_index();
注意头文件中的预定义宏:
#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif
在动态库设置预定义宏,
添加项目,MathLibrary.cpp
// MathLibrary.cpp : Defines the exported functions for the DLL.
#include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
#include <utility>
#include <limits.h>
#include "MathLibrary.h"
// DLL internal state variables:
static unsigned long long previous_; // Previous value, if any
static unsigned long long current_; // Current sequence value
static unsigned index_; // Current seq. position
// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
void fibonacci_init(
const unsigned long long a,
const unsigned long long b)
{
index_ = 0;
current_ = a;
previous_ = b; // see special case when initialized
}
// Produce the next value in the sequence.
// Returns true on success, false on overflow.
bool fibonacci_next()
{
// check to see if we'd overflow result or position
if ((ULLONG_MAX - previous_ < current_) ||
(UINT_MAX == index_))
{
return false;
}
// Special case when index == 0, just return b value
if (index_ > 0)
{
// otherwise, calculate next sequence value
previous_ += current_;
}
std::swap(current_, previous_);
++index_;
return true;
}
// Get the current value in the sequence.
unsigned long long fibonacci_current()
{
return current_;
}
// Get the current index position in the sequence.
unsigned fibonacci_index()
{
return index_;
}
相关文献:
演练:创建和使用自己的动态链接库 (C++)
创建静态库
具体参见《演练:创建并使用静态库》,这里不再详述。
动态库与静态库的区别
名称不同:
静态库:.lib
动态库:.dll
链接方式不同:
静态库采用静态链接方式,在程序链接阶段,静态库与汇编生成的目标文件一起打包到程序可执行文件*.exe中。
静态库对函数库的链接是在编译阶段完成的,运行时与函数库没有关系了。
所有的目标文件和函数库都会链接到程序可执行文件中,比较浪费空间和资源。
动态库在编译时并不会被链接到目标代码中,而是在程序运行的时候才被载入。
动态链接方式==》动态链接又包括显示链接和隐士链接。
多个程序引用
当一个静态库A被多个程序使用时,每个程序都会有A的一个拷贝,比较浪费空间。
不同程序使用相同的动态库,动态库在内存中只有一份实例,可以实现进程之间资源共享。==》动态库也叫做共享库。
程序更新:
如果静态库更新了,所有使用它的程序都需要重新编译。
注意:
静态库的lib和动态库的lib不是一个概念,
静态库的lib叫做静态库,动态库里面的lib叫做导入库。
静态库lib包含实际执行代码和符号表等;导入库,实际执行代码在动态库中,导入库只包含了地址符号表等。
相关文献:
C++静态库与动态库
动态链接与静态链接的区别
相关文献
深入浅出静态链接和动态链接
动态库的加载过程
dll的创建以及应用程序隐式链接到dll的过程
- 头文件中,包含导出函数的原型、结构和符号的说明
- c/c++源文件,其中包含待导出函数的实现和变量
- 编译器为每个源文件生成.obj文件
- 链接器将为每个obj模块合并,生成dll
- 如果至少导出一个函数或变量,链接器同时生成lib文件
构建exe - 头文件,包含导出函数的原型、结构和符号的声明
- 源文件,包含待导出函数的实现和变量
- 编译器为每个源文件生成obj文件
- 链接器将每个obj模块合并,并使用lib文件来解析导入的函数/变量的引用,从而生成exe。(它包含一个导入表,其中列出了必需的dll和导入的符号)
运行应用程序
加载程序创建地址空间
加载程序将必需的dll载入到地址空间
进程的主线程开始执行,应用程序开始执行
dll的创建以及应用程序显示链接到dll的过程
- 头文件中,包含导出函数的原型、结构和符号的说明
- c/c++源文件,其中包含待导出函数的实现和变量
- 编译器为每个源文件生成.obj文件
- 链接器将为每个obj模块合并,生成dll
- 如果至少导出一个函数或变量,链接器同时生成lib文件(显示链接没有用到这个lib文件)
构建exe - 头文件,包含导出函数的原型、结构和符号的声明
- 源文件,包含待导出函数的实现和变量
- 编译器为每个源文件生成obj文件
- 链接器将每个obj模块合并,从而生成exe。(由于没有直接引用dll的导入符号,因此这里不需要它的lib文件,生成的exe不包含导入表)
运行应用程序 - 加载程序创建地址空间 进程的主线程开始执行,应用程序开始执行
- 线程调用loadLiberay来将dll载入到进程的地址空间中。
- 各个线程可以调用GetProAddress来简接地引用dll导出的符号。