静态链接库和动态链接库

来源:互联网 发布:mac待机时间设置 编辑:程序博客网 时间:2024/06/03 18:52
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  • 静态链接库(lib):静态库是一个或者多个obj文件的打包,从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。代码中不需要任何关键字来导出函数。
  • 动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。动态库一般会有对应的导入库(lib),方便程序隐式载入动态链接库,否则你可能就需要自己LoadLibary调入DLL文件,然后再手工GetProcAddress获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。 代码中有关键字__declspec(dllexport)导出函数或者用def文件导出函数。
  • 动态链接库与静态链接库的区别:在于它允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。在静态链接库中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。 
  • 使用动态链接代替静态链接有若干优点。DLL 节省内存,减少交换操作,节省磁盘空间,更易于升级,提供售后支持,提供扩展 MFC 库类的机制,支持多语言程序,并使国际版本的创建轻松完成。
  • 导入库和静态链接库的区别很大。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息
  • 静态链接库调用方法:首先#include "xxx.h",其次#pragma comment(lib,"xxx.lib") 或者 project settting里将xxx.lib加入到additional dependencies.
  • 动态链接库调用方法:(1)加载时链接:应用程序像调用本地函数一样对导出的 DLL 函数进行显式调用。要使用加载时动态链接,请在编译和链接应用程序时提供头文件 (.h) 和导入库文件 (.lib)。当您这样做时,链接器将向系统提供加载 DLL 所需的信息,并在加载时解析导出的 DLL 函数的位置。即需要向静态链接库一样的调用方法,只是需要多了copy了一个dll到应用程序那边。 (2)运行时链接:应用程序调用 LoadLibrary 函数或 LoadLibraryEx 函数以在运行时加载 DLL。成功加载 DLL 后,可以使用 GetProcAddress 函数获得要调用的导出的 DLL 函数的地址。在使用运行时动态链接时,不需要#include "xxx.h",以及导入库(lib),只要dll即可。如果dll导出时使用extern "C",则GetProcAddress()里面的函数名就是初始导出的函数名(如myMin);如果如果dll导出时没有使用extern "C",则GetProcAddress()需要mangling name(可以通过dependency walker打开dll来找到)。
  • 调用静态库或者动态库的应用程序的calling convention应该与静态库或者动态库的calling convention一致(_cdcel,_stdcall等)。
  • 一般导出dll的.h文件可以写成如下,以便可以在dll和调用dll的application中同时使用(通过定义宏
    EXPORTING_DLL来区别)。
#ifdef EXPORTING_DLL 
extern __declspec(dllexport) int mySum(int x, int y); 
#else 
extern __declspec(dllimport) int mySum(int x, int y); 
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1.什么是静态连接库,什么是动态链接库         静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接 库。静态链接库与静态链接库调用规则总体比较如下。

对于静态链接库(比较简单):首先,静态链接库的使用需要库的开发者提供生成库的.h头文件和.lib文件。生成库的.h头文件中的声明格式如下:extern "C" 函数返回类型 函数名(参数表);在调用程序的.cpp源代码文件中如下:#include "../lib.h"#pragma comment(lib,"..//debug//libTest.lib") //指定与静态库一起链接第二,因为静态链接库是将全部指令都包含入调用程序生成的EXE文件中。因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况,要想用就得全要!要不就都别要!:)

 

对于动态链接库:动态链接库的使用,根据不同的调用方法,需要提供不同的资源:

1. 静态加载------程序静态编译的时候就静态导入dll,这样的话就需要提供给库使用者(C客户)如下文件:*.lib文件和.dll文件和*.h。其有2个坏处:

    1   程序一开始运行就需要载入整个dll,无法载入程序就不能开始运行;     2   由于载入的是整个dll,需要耗费资源较多

其调用方法如下:

#include "../lib.h"#pragma comment(lib,"..//debug//libTest.lib")

            但是这种方式的话可以调用Class method.

2.动态加载-----那么只需要提供dll文件。

因此调用程序若想调用DLL中的某个函数就要以某种形式或方式指明它到底想调用哪一个函数。但是无法调用Class method了。如果要调用Dll中的function,需要经历3个步骤:Handle h=LoadLibrary(dllName) --> GetProcAddress(h,functionName) 返回函数指针,通过函指针调用其function-->FreeLibrary(h)例如:Another.dll有一个int Add(int x,int y)函数。则完整的调用过程如下:typedef int (* FunPtr)(int,int);//定义函数指针FunPtr funPtr;Handle h=LoadLibrary("Another.dll");funPtr=(FunPtr)GetProcAddress(h,"Add");funPtr(2,3);//2+3;FreeLibrary(h);

 

2.示例示例之一:静态链接库的创建过程:例如:我们创建一个自定义字符串的类CHironString,只需要在IDE里面添加class即可,然后program相应函数体代码如下所示:SDLL.h文件------------------------------------------------------------------------// HironString.h: interface for the CHironString class.////////////////////////////////////////////////////////////////////////

#if !defined(AFX_HIRONSTRING_H__B23C5E5E_0E8B_4030_B057_34A40C934C59__INCLUDED_)#define AFX_HIRONSTRING_H__B23C5E5E_0E8B_4030_B057_34A40C934C59__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000

class CHironString  {private:

 char* m_data;public: char * GetData(); CHironString(CHironString &other); int Length();  CHironString(); CHironString(char * str); CHironString& operator=(CHironString &other); virtual ~CHironString();};

#endif // !defined(AFX_HIRONSTRING_H__B23C5E5E_0E8B_4030_B057_34A40C934C59__INCLUDED_)

SDLL.CPP如下:--------------------------------------------------------------// HironString.cpp: implementation of the CHironString class.////////////////////////////////////////////////////////////////////////

#include "stdafx.h"#include "HironString.h"

//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////

CHironString::CHironString(){ m_data=NULL;}

CHironString::CHironString(char * str){ int len=strlen(str); m_data=new char[len+1]; strcpy(m_data,str);

}

CHironString::~CHironString(){ delete m_data;}

int CHironString::Length(){ return strlen(m_data);}

CHironString::CHironString(CHironString &other){ int len=strlen(other.m_data)+1; m_data=new char[len]; strcpy(m_data,other.m_data);}

CHironString& CHironString::operator =(CHironString &other){ if(this==&other)  return *this; if(m_data!=NULL)  delete[] m_data; int len=strlen(other.m_data)+1; m_data=new char[len]; strcpy(m_data,other.m_data); return *this;}

char * CHironString::GetData(){ return m_data;}

然后,将程序编译后生成sdll.lib。客户调用:将CHironString.h和SDLL.lib发布给client,那么客户端就可以调用我们编写的静态链接库了。示例之二:动态链接库的创建

首先我们必须先注意到DLL内的函数分为两种: (1)DLL 导出函数,可供应用程序调用; (2)DLL 内部函数,只能在 DLL 程序使用,应用程序无法调用它们。

我们还是创建一个自定义的字符串处理类CHironString,不同之处其是一个动态链接库Dll。动态链接库的export 需要在在相应的头文件中编写相应的MACROMyDll.h:自定义了一些类(函数)export 宏(该文件由IDE自动生成)如下------------------------------------------------------------------#ifdef MYDLL_EXPORTS#define MYDLL_API __declspec(dllexport)#else#define MYDLL_API __declspec(dllimport)#endif这是导出类的宏定义,将导出类必须加上该宏,才能被导出。此处的MYDLL_EXPORTS会出现在 project-->settings-->C/C++页面上的 PreProcessor definition中,这个MACRO表明其要定义一个导出宏CHironString.h 自定义类头文件----------------------------------------------------------------// HironString.h: interface for the CHironString class.////////////////////////////////////////////////////////////////////////

#if !defined(AFX_HIRONSTRING_H__518E9EC4_0837_4E45_9516_7D6A70CD3D0F__INCLUDED_)#define AFX_HIRONSTRING_H__518E9EC4_0837_4E45_9516_7D6A70CD3D0F__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include "MyDll.h"

class MYDLL_API CHironString   //加上MYDLL_API表明此为Export Class{private:

 char* m_data;public: char * GetData(); CHironString(CHironString &other); int Length();  CHironString(); CHironString(char * str); CHironString& operator=(CHironString &other); virtual ~CHironString();

};

#endif // !defined(AFX_HIRONSTRING_H__518E9EC4_0837_4E45_9516_7D6A70CD3D0F__INCLUDED_)

 CHironString.Cpp------------------------------------------------------------

// HironString.cpp: implementation of the CHironString class.////////////////////////////////////////////////////////////////////////

#include "stdafx.h"#include "HironString.h"

//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////

CHironString::CHironString(){ m_data=NULL;}

CHironString::CHironString(char * str){ int len=strlen(str); m_data=new char[len+1]; strcpy(m_data,str);

}

CHironString::~CHironString(){ delete m_data;}

int CHironString::Length(){ return strlen(m_data);}

CHironString::CHironString(CHironString &other){ int len=strlen(other.m_data)+1; m_data=new char[len]; strcpy(m_data,other.m_data);}

CHironString& CHironString::operator =(CHironString &other){ if(this==&other)  return *this; if(m_data!=NULL)  delete[] m_data; int len=strlen(other.m_data)+1; m_data=new char[len]; strcpy(m_data,other.m_data); return *this;}

char * CHironString::GetData(){ return m_data;}

 

经过compile之后,会生成MyDll.dll和MyDll.lib文件。客户端的调用:1.如果是静态加载,那么需要提供*.lib和*.h,运行时候需提供*.dll

2.如果是动态加载,只需要提供*.dll即可

0 0
原创粉丝点击