采用VS2013创建静态库和动态库
认识静态库和动态库
静态库(静态链接库)、动态库(动态链接库)的作用都是实现代码共享和复用,它们基本概念如下:
静态库:在链接步骤中,链接器将从库文件取得所需的代码,复制到生成的可执行文件中,这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。即静态库中的指令都全部被直接包含在最终生成的 EXE 文件中了。在vs中新建生成静态库的工程,编译生成成功后,只产生一个.lib文件(如何区分release和debug,或者说是否区分release和debug有待进一步验证)。
动态库:动态链接库是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。在vs中新建生成动态库的工程,编译成功后,产生一个.lib文件和一个.dll文件(动态库是要区分release和debug的)。
一 静态链接库
1.1创建静态链接库
(1)文件-新建-项目——选择“win32项目”—填写项目“名称”:mylib—点击“确定”——下一步——应用程序类型:选择“静态库”,其余默认选择;
(2)VS平台自动创建了3个文件(2个h文件,1个cpp文件):stdafx.h、targetver.h、stdafx.cpp;
(3)我们需要做的就是手动添加(新建)两个文件mylib.h和mylib.cpp。
头文件mylib.h:
#ifndef MYLIB_H
#define MYLIB_H
void fun(int a); //自定义功能函数
extern int k; //extern 这个关键字的作用:https://www.cnblogs.com/yuxingli/p/7821102.html
class testclass //自定义类
{
public:
testclass();
void print();
};
#endif
源文件mylib.cpp:
#include "stdafx.h"
#include "mylib.h"
#include <iostream>
void fun(int a)
{
std::cout << a << " mylib generator!\n";
}
int k = 222;
testclass::testclass()
{
std::cout << "testclass\n";
}
void testclass::print()
{
std::cout << "this is testcalss function:print()\n";
}
(4)生成解决方案,就会生成一个.lib文件
1.2 使用静态库
需要.h文件,lib文件
(1)设置项目属性–VC++目录–库目录:lib文件所在的目录;比如:mylib\libdebug,mylib\librelease
(2)设置项目属性–链接器–输入–附加依赖项:mylib.lib;或者直接在源代码中加入 #pragma comment(lib, “**.lib”)
(3)设置项目属性–VC++目录–包含目录:h头文件所在目录(也可以在设置项目属性–C/C+±-常规–附加包含目录),在目标源文件中添加h头文件;为了方便管理可以将每一个库的所有文件分类存在一个文件夹下,比如:mylib\include
(4)然后,在目标项目中像平常一样调用普通函数、类、变量,比如:
// testlib.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "iostream"//命名空间std所在的头文件
#include "mylib.h"
#pragma comment(lib, "mylib.lib") //设置这句话后就不需要设置项目链接器属性了
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
fun(4);
std::cout << k << std::endl;
testclass tc;
tc.print();
system("pause"); //调试F5是可以阻塞显示控制台窗口
return 0;
}
二 动态链接库
2.1 创建动态链接库
(1)文件-新建-项目——选择“win32项目”—填写项目“名称”:mydll—点击“确定”——下一步——应用程序类型:选择DLL、附加选项:加选择“导出符号”—点击“完成”;
(2)VS平台自动创建了6个文件(3个h文件,3个cpp文件):myll.h、stdafx.h、targetver.h,dllmain.cpp、mydll.cpp、stdafx.cpp;
(3)我们需要做的就是在头文件myll.h和源文件mydll.cpp中添加自己的变量、函数和类。
头文件实例:
// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 MYDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// MYDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
#include <iostream> //自主这引用头文件,根据需要添加
#include <string> //自主这引用头文件,根据需要添加
using namespace std;
// 此类是从 mydll.dll 导出的
class MYDLL_API Cmydll { //Cmydll是用户自定义类名
public:
Cmydll(void);
// TODO: 在此添加您的方法。
int setname(string name);
int setnum(int num);
int setperunit(int perunit);
int printinfo();
int getcost();
private:
string m_name;
int m_num;
int m_perunit;
};
extern MYDLL_API int nmydll; //自定义全局变量
MYDLL_API int fnmydll(void); //自定义函数形式
// 自定义整数加法和乘法
MYDLL_API int _Add(int a, int b);
MYDLL_API int _Mul(int c, int d);
源文件实例:
// mydll.cpp : 定义 DLL 应用程序的导出函数。
// 函数声明
#include "stdafx.h"
#include "mydll.h"
// 这是导出变量的一个示例
MYDLL_API int nmydll=1;
// 这是导出函数的一个示例。
MYDLL_API int fnmydll(void)
{
return 22;
}
MYDLL_API int _Add(int a, int b) //注意:关键词MYDLL_API省略似乎也没有太大影响。
{
return a + b;
}
MYDLL_API int _Mul(int c, int d)
{
return c*d;
}
// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 mydll.h
Cmydll::Cmydll()
{
return;
}
int Cmydll::setname(string name)
{
m_name = name;
return 0;
}
int Cmydll::setnum(int num)
{
m_num = num;
return 0;
}
int Cmydll::setperunit(int perunit)
{
m_perunit = perunit;
return 0;
}
int Cmydll::printinfo()
{
cout << "name: " << m_name << endl;
cout << "num: " << m_num << endl;
cout << "perunit: " << m_perunit << endl;
return 0;
}
int Cmydll::getcost()
{
int cost = m_num*m_perunit;
return cost;
}
(4)在对应配置条件(release或debug)下,生成解决方案,生成mydll.dll 和mydll.lib;出现一个警告:
“ warning C4251: “Cmydll::m_name”:class“std::basic_string<char,std::char_traits< char > ,std::allocator< char > >” 需要有 dll 接口由 class“Cmydll”的客户端使用 ”,暂时不影响生产库文件。
2.2 使用动态链接库
调用动态库:隐式链接(比较常用的一种方式)
需要.h文件,dll文件,lib文件(release和debug配置环境下生产的文件要区分开,分别应用于目标程序的release和debug配置参数)
(1)将dll放到工程的工作目录(.\Visual Studio 2013\Projects\testmydll\testmydll),推荐存放在调试输出目录中(.\Visual Studio 2013\Projects\testmydll\Debug)
(2)设置项目属性–VC++目录–包含目录:h头文件所在目录(也可以在设置项目属性–C/C+±-常规–附加包含目录),在目标源文件中添加h头文件;为了方便管理可以将每一个库的所有文件分类存在一个文件夹下,比如:mydll\include
(3)设置项目属性–VC++目录–库目录:lib文件所在的目录;比如:mydll\libdebug,mydll\librelease
(4)设置项目属性–链接器–输入–附加依赖项:mydll.lib;或者直接在源代码中加入 #pragma comment(lib, “**.lib”)
(5)在目标项目中,像通常一样调用普通函数、类、变量,比如:
// testmydll.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "mydll.h"
int _tmain(int argc, _TCHAR* argv[])
{
Cmydll mydll1;
mydll1.setname("liuwei");
mydll1.setnum(10);
mydll1.setperunit(2);
int getv=mydll1.getcost();
mydll1.printinfo();
nmydll = 2;
int result;
result=_Add(5, 1);
result=_Mul(3, 5);
system("pause"); //作用:在启动调试的时候(F5)不会出现一闪而过的现象
return 0;
}
注意:
① 开发32位和64位程序需要的库,需要创建和引用对应配置的库,即32位程序引用win32配置下创建的库,64位程序引用x64配置下创建的库。
② release和debug版本的程序同样需要配置对应版本的库,即release程序引用release版本的库,debug程序引用debug版本的库。