C++链接库
静态链接库在程序编译链接过程中就导入lib文件并且包含在生成的exe文件里,而动态链接库DLL是在程序运行中由程序加载和卸载的,也就是说它是动态的,当然动态链接库DLL也可以静态加载当做静态来用;
静态链接库使用方便直接,但程序内存占用大、使用不灵活,而动态链接库使用灵活但加载需要时间。
静态链接库
本文使用VC++6.0集成工具,新建一个Win32 Static Library工程,再新建一个如下cpp文件,完成构建之后可以得到一个lib文件,这就是之后的应用程序要用到的文件;
//--********* libTest.cpp **********--//
//----------- 声 明 一 个 函 数,并 按 C 方 式 编 译 连 接 ---------
extern "C" int getNumber();
int getNumber()
{
return ;
}
构建之后,静态连接库就算创建完成了,在lib文件中可以找到"_getNumber",这就是"C"编译方式的函数名;如果声明的函数名之前加上__stdcall",
即声明:int __stdcall getNumber();那么lib文件中可以见到"?getNumber@@YGHHH@Z",这就是C++编译方式的函数名(方便函数重载)。另外的以__cdecl(缺省)和__fastcall编译之后的命名方式也类似。
然后新建一个工程,把头文件libTest.h和库文件libTest.lib复制到新工程文件夹下,主程序代码如下:
#include <stdio.h>
#include "libTest.h"
//--------- 把 要 用 到 的 外 部 链 接 文 件 和 本 地 obj 文 件 一 同 构 建 ------
//--------- 如 果 不 复 制 ,则 这 里 使 用 全 路 径 指 向 库 工 程 的 lib ---
#pragma comment(lib,"libTest.lib") int main(int argc, char* argv[])
{
printf("Number: %d\n", getNumber());
return ;
}
程序运行结果如下:
动态链接库
/*** 新建 一 个 dynamic~link Libbrary 工 程 dllTest *******
**** 添 加 一 个 dllTest.cpp 文 件 *****
*/
//-------------- 声 明 并 导 出 函 数 -------
extern "C" __declspec(dllexport) int add(int x, int y);
//__declspec(dllexport)int __stdcall add(int,int); int add(int x, int y)
{
return x + y;
}
创建一个动态链接库时,需要把其中的方法导出,并生成dll文件,上述的__declspec(dllexport)是一种导出方式;
或者可以用def文件导出,新建一def文件,并添加文件到工程就行了,其全部的代码如下:
LIBRARY dllTest
EXPORTS
add @
其中add是函数名,1是序号;这样构建之后也可以得到一个dll文件。
新建一个应用工程,把生成的dll文件复制到工程文件夹下,主函数如下:
#include <stdio.h>
#include <windows.h>
//------------- 根 据 之 前 导 出 的 形 式 定 义 一 个 函 数 指 针 类 型 -----------
typedef int (*lpAddFun)(int,int);
//typedef int (__stdcall *lpAddFun)(int,int);
int main(int argc, char* argv[])
{
//-------------- 用 定 义 的 函 数 指 针 类 型 创 建 一 个 函 数 ------
lpAddFun add;
//--------------- 加 载 动 态 链 接 库 ---------
HINSTANCE hDll = LoadLibrary("dllTest.dll");
if(hDll)
{
//----------------- 可 以 用 函 数 名 导 入,也 可 以 用 序 号 来 导 入--------
add = (lpAddFun)GetProcAddress(hDll, "add");
//add = (lpAddFun)GetProcAddress(hDll, MAKEINTRESOURCE(1));
if(add) printf("5 + 7 = %d\n", add(, ));
//----------------- 卸 载 链 接 库 -----------
FreeLibrary(hDll);
}
return ;
}
程序运行结果如下:
dll的静态调用方式
动态链接库的创建方式相同,但是使用时,需要复制dll文件、lib文件两个文件到应用工程文件夹下,主函数代码如下:
#include <stdio.h>
#pragma comment(lib, "dllTest.lib")
//-------------- 以 "C" 方 式 导 出 的 函 数 ,这 里 就 要 以 "C" 的 方 式 导 入 ----------
//-------------- 或 者 导 出 时 不 加 extern "C" ,这 里 也 不 加( 缺 省 __cdecl ) -------------
//-------------- 也 就 是 说 导 入 和 导 出 的 方 式 必 须 一 致(注意!) ------------------
extern "C" __declspec(dllimport) int add(int, int);
//__declspec(dllimport)int __stdcall add(int,int);
int main()
{
printf("12 + 25 = %d\n", add(, ));
return ;
}
两种调用方式的对比:
(1) 静态调用的add(),是通过dllTest.lib文件索引到dllTest.dll文件中的add();
(2) 动态调用方式是在程序运行时,直接加载dll文件,导出其中的add()方法并给函数指针赋值,通过函数指针调用函数。
函数DllMain
Windows加载dll时需要一个入口函数DllMain(),当dll文件中没有DllMain()函数时,会调用一个缺省的无任何操作的DllMain(),它是由系统调用的,不能手动调用。
#include "dllTest.h"
#include <stdio.h>
#include <windows.h> BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("dll process attach\n");
break;
case DLL_THREAD_ATTACH:
printf("dll thread attach\n");
break;
case DLL_PROCESS_DETACH:
printf("dll process detach\n");
break;
case DLL_THREAD_DETACH:
printf("dll process detach\n");
break;
}
return TRUE;
} int add(int x, int y)
{
return x + y;
}
这是一个DllMain()使用实例,其中ul_reason_for_call代表dll的四种调用方式,包括两种加载和两种卸载;
用前面的应用程序实验之后,结果如下:
导出类class
class CPoint
{
public:
float x;
float y; virtual void add(float, float) = ;
virtual float getX() = ;
virtual float getY() = ;
}; class CMyPoint : public CPoint
{
public:
CMyPoint(float, float);
virtual void add(float, float);
virtual float getX();
virtual float getY();
}; class __declspec(dllexport)CMyPoint;
设计一对父类——子类,父类中的方法设计成纯虚函数,而它的子类就是我们要用的类了,在dll中工程中导出的也是子类CMyPoint,上面最后一句代码导出这个子类。
这是子类的实现代码:
CMyPoint::CMyPoint(float x0, float y0)
{
var = ;
x = x0;
y = y0;
} void CMyPoint::add(float dx, float dy)
{
x = x + dx;
y = y + dy;
} float CMyPoint::getX()
{
return x;
} float CMyPoint::getY()
{
return y;
}
CMyPoint.cpp
类CMyPoint的实现还包含一个Create函数,是用来创建类对象的。这个方法也应该用C方式导出,否则使用起来有些麻烦。
extern "C" __declspec(dllexport)CMyPoint* CreatePoint(float,float);
CMyPoint* CreatePoint(float x0, float y0)
{
return (new CMyPoint(x0, y0));
}
动态加载方式
新建应用工程,需要复制.h头文件、dll文件到新的工程文件夹下,程序先获取CreatePoint()方法,再通过它创建类CMyPoint并返回一个对象指针,接下来便可以操作这个类对象;
注意:应用工程文件夹下的dllTest.h中不能有多余的导出或者导入语句,可以用宏屏蔽,也可以手动删除。
#include "dllTest.h" typedef CMyPoint*(*lpCreatePoint)(float,float); int main(int argc, char* argv[])
{
lpCreatePoint CreatePoint;
HINSTANCE hDll = LoadLibrary("dllTest.dll");
if(hDll)
{
CreatePoint = (lpCreatePoint)GetProcAddress(hDll, "CreatePoint");
if(CreatePoint)
{
CMyPoint* p0 = CreatePoint(, );
printf("x = %.2f, y = %.2f\n", p0->getX(), p0->getY());
}
FreeLibrary(hDll);
}
return ;
}
静态加载方式
静态使用方式很简单,同样应用创建函数CreatePoint(),而且是导出后直接使用,当然类界面还是必须inlclude;
#include "dllTest.h"
#pragma comment(lib, "E:\\VC6\\dllTest\\Debug\\dllTest.lib") extern "C" __declspec(dllimport)CreatePoint(float,float);
int main()
{
CMyPoint* p0 = CreatePoint(, );
p0->add(, ); printf("x = %.2f, y = %.2f\n", p0->getX(), p0->getY()); return ;
}
静态导入方式构建生成的EXE文件可移植,lib文件和dll文件在构建时都固化在其中,所以这里生成的EXE无论到哪儿,只要系统还兼容,程序就可以运行;
而之前的动态导入方式,dll文件需要随着EXE文件移动,不然程序运行时会找不到dll文件而出错,所以我们一般的见到的软件安装目录下都有一大堆dll文件。
导出变量
在dll工程中,导出:int __declspec(dllexport)varName;
在应用工程中,导入:int __declspec(dllimport)varName;
其中,int是变量类型,varName是变量名,
C++链接库的更多相关文章
- vc下的静态链接库与动态链接库(一)
一.静态库与动态库的区别 目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Lib ...
- C/C++ 静态链接库(.a) 与 动态链接库(.so)
平时我们写程序都必须 include 很多头文件,因为可以避免重复造轮子,软件大厦可不是单靠一个人就能完成的.但是你是否知道引用的那些头文件中的函数是怎么被执行的呢?这就要牵扯到链接库了! 库有两种, ...
- ZeroMQ接口函数之 :zmq_version – 返回ZMQ链接库的版本
ZeroMQ 官方地址 :http://api.zeromq.org/4-2:zmq_version zmq_version(3) ØMQ Manual - ØMQ/4.1.0 Na ...
- VS2010编译Boost 1.57 静态链接库
http://www.cnblogs.com/cuish/p/4175491.html 0.前提 Boost库版本 1.57.0 下载地址 http://www.boost.org/users/his ...
- Linux 下安装mysql 链接库
1.mysql 客户端 开发 链接库 1.1)CentOS yum install mysql-devel
- 利用GCC编译器生成动态链接库和静态链接库
转载请标明:http://www.cnblogs.com/winifred-tang94/ 1.编译过程 gcc –fPIC –c xxx.c 其中-fPIC是通知gcc编译器产生位置独立的目标代码. ...
- Windows 下动态链接库和静态链接库
1.静态链接库:就是在编译的时候把库中代码复制进工程中,导致工程变大,但是速度快. 缺点在于一套代码可能在内存中有多份拷贝,占用内存. 2.动态链接库:库由windos api加载库代码,内存中只有一 ...
- App开发流程之数据持久化和编译静态链接库
先记录数据持久化. iOS客户端提供的常用数据持久化方案:NSUserDefaults代表的用户设置,NSKeydArchiver代表的归档,plist文件存储,SQLite数据库(包括上层使用的Co ...
- 链接库lib和dl的概念,加载方式的区别
使用LR进行基于windows socket协议做接口测试,只提供了lr_load_dll方法来动态加载动态链接库.之前学习阶段,对TinyXML的学习,使用的静态链接库,当时在程序调用的时候方法也跟 ...
- Linux链接库四(多个库文件链接顺序问题)
最近在Linux下编程发现一个诡异的现象,就是在链接一个静态库的时候总是报错,类似下面这样的错误: (.text+0x13): undefined reference to `func' 关于unde ...
随机推荐
- C# 使用XmlDocument类对XML文档进行操作
原创地址:http://www.cnblogs.com/jfzhu/archive/2012/11/19/2778098.html 转载请注明出处 W3C制定了XML DOM标准.很多编程语言中多提供 ...
- 【线段树】【4-6组队赛】Problem H
Problem Description #include <iostream> #include <algorithm> using namespace std; int n, ...
- 温故而知新之数据库的分离和附加…高手请跳过….
sql server2005分离数据库后,把路径下的两个文件拷到自己想要存放的目录下,然后再附加
- 折叠Collapse插件
实例 折叠(Collapse)插件可以很容易地让页面区域折叠起来.无论您用它来创建折叠导航还是内容面板,它都允许很多内容选项. .collapse 隐藏内容. .collapse.in 显示内容. . ...
- 剑指offier77页
/* * 输入字母判断第几列 */ import java.util.Scanner; public class JudgeClumns { public static void main(Strin ...
- U3D学习使用笔记(三)
1.对动画进行播放和暂停(从初始位置) (1).老版动画系统Animation 暂停 an["Take 001"].time = 0f; an["Take 001&quo ...
- [分 享] PHPCMS V9 更换域名,附件地址无法批更新(更换变便)问题>解决方法!!
大家应该都有在域名更换(比如说,从本地上传到空间)的情况下,用内容>附件管理>附件地址替换 功能. 基本上替换不了所有表中原来域名的地址. 现PHPCMS V9最新版本的依旧存在些问题. ...
- Linux下多任务间通信和同步-消息队列
Linux下多任务间通信和同步-消息队列 嵌入式开发交流群280352802,欢迎加入! 简介 消息队列简称为队列.消息队列就是一些消息的列表.用户可以在消息队列中添加消息和读取消息等.从这点上看,消 ...
- php中如何输出当前服务器的(中国)当前时间
date_default_timezone_set('PRC');//PRC是什么?PRC是中华人民共和国啊-_- echo "今天是".date("Y年m月d日&quo ...
- xampp环境安装swoole
手动编译php运行环境经常遇到函数库依赖的问题,这个错误搞定了,又蹦出来那个错误,很棘手,为了快速搭建一个swoole开发环境,于是另辟蹊径,直接下载安装xampp for linux,然后在用xam ...