动态、静态链接库小结

来源:互联网 发布:淘宝口罩男生 编辑:程序博客网 时间:2024/05/06 00:22

一、静态链接库版本一致性

1、开发工具版本间一致;

2、Debug、Release版本间一致;

3、Unicode版本间一致(库编译采用的字符集:Unicode、多字节等);

4、调用VC运行时库(MSVCRTXX.dll)一致。

二、静态链接库的命名规则

举例:Skin++静态链接库的命名规则

1. SkinPPStatic为Skin++静态链接库的前缀缩写 ;

2. S 为静态链接MFC或静态调用运行时库、D为动态链接MFC或动态调用运行时库。

以VC6为例,在工程设置的C++ 页面的"Use run-time &library:"段中可以看到其设置,如果在下边的ComboBox框中选择的名称后面带DLL的,那么说明你们的工程是动态调用运行时库,如果没有带DLL文字,那就说明是静态调用运行时库。一般情况下,用户不需要改变其设置,该设置会随着选择静态链接MFC或动态链接MFC的改变而改变。如果当前工程是静态链接MFC的,那么你的工程就是静态调用运行时库,如果是动态链接MFC的,那么就是动态调用运行时库。如果你的程序是Win32 SDK,那么这个时候,你需要自己来确定选择哪种方式来调用运行时库,并选择合适的Skin++ 静态链接库。

3.R为Release的意思。由于静态链接库必须保证Release版本的静态库对应Release版本的调用程序,Debug版本的静态库对应Debug版本的调用程序,所以Skin++ 为不同的版本提供了相对应的Skin++ 静态链接库。

D为Debug的意思。

4.A为ANSI编码方式。U为Unicode编码方式。Skin++提供了2种编码方式的静态库。

5.静态链接库还必须要求开发工具的一致性。就是如果调用者是VC6工程,那么静态库也必须是VC6编译而成的。

 

静态链接库LIB和动态链接库DLL的区别 创建和示例

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 需要在在相应的头文件中编写相应的MACRO
MyDll.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即可。

一、分别编译与链接(Linking

大多数高级语言都支持分别编译,程序员可以显式地把程序划分为独立的模块或文件,然后每个独立部分分别编译。在编译之后,由链接器把这些独立的片段(称为编译单元)“粘接到一起”。(想想这样做有什么好处?)

C/C++中,这些独立的编译单元包括obj文件(一般的源程序编译而成)、lib文件(静态链接的函数库)、dll文件(动态链接的函数库)等。

静态链接方式:在程序执行之前完成所有的组装工作,生成一个可执行的目标文件(EXE文件)。

动态链接方式:在程序已经为了执行被装入内存之后完成链接工作,并且在内存中一般只保留该编译单元的一份拷贝。

二、静态链接库与动态链接库

先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终的EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。

采用动态链接库的优点:(1)更加节省内存;(2DLL文件与EXE文件独立,只要输出接口不变,更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性。

三、静态链接库的制作

对静态链接库的讲解不是本文的重点,但是在具体讲解DLL之前,通过一个静态链接库的例子可以快速地帮助我们建立“库”的概念。

1 建立一个静态链接库

如图1,在VC++6.0new一个名称为libTeststatic library工程,并新建lib.hlib.cpp两个文件,lib.hlib.cpp的源代码如下:

//文件:lib.h

#ifndef LIB_H

#define LIB_H

extern "C" int add(int x,int y);   //声明为C编译、连接方式的外部函数

#endif

//文件:lib.cpp

#include "lib.h"

int add(int x,int y)

{

return x + y;

}

编译这个工程就得到了一个libTest.lib文件,这个文件就是一个函数库,它提供了add的功能。将头文件lib.hlibTest.lib文件提交给用户后,用户就可以直接使用其中的add函数了。常用的标准C库函数(scanfprintfmemcpystrcpy等)就来自这种静态库。

四、静态链接库的调用

下面来看看怎么使用这个库。在VCnew一个名为libCallWin32 Console Application工程,并将上面生成的文件lib.hlibTest.lib文件拷贝到libCall的工程子目录下。libCall工程仅包含一个main.cpp文件,它演示了静态链接库的调用方法,其源代码如下:

#include <stdio.h>

#include "lib.h"

#pragma comment( lib, "libTest.lib" )   //指定与静态库一起连接

int main()

{

printf( "2 + 3 = %d", add( 2, 3 ) );

}

静态链接库的调用就是这么简单,或许我们每天都在用,可是我们没有明白这个概念。代码中#pragma comment( lib , "libTest.lib" )的意思是指本文件生成的.obj文件应与libTest.lib一起连接。

如果不用#pragma comment指定,则可以直接在VC++中设置,如图2,依次选择toolsoptionsdirectorieslibrary files菜单或选项,填入库文件路径。图2中加圈的部分为我们添加的libTest.lib文件的路径。

2 VC中设置库文件路径

这个静态链接库的例子至少让我们明白了库函数是怎么回事,它们是哪来的。我们现在有下列模糊认识了:

1)库不是个怪物,编写库的程序和编写一般的程序区别不大,只是库不能单独执行;

2)库提供一些可以给别的程序调用的东东,别的程序要调用它必须以某种方式指明它要调用之。

以上从静态链接库分析而得到的对库的懵懂概念可以直接引申到动态链接库中,动态链接库与静态链接库在编写和调用上的不同体现在库的外部接口定义及调用方式略有差异。

---------------------------------------------------------------------------------------------------

以下为接静态链接库与动态链接库(下)未完部分:

九、动态链接库的应用举例

1、所有的Windows系统调用(Windows API函数)都是以动态链接库的形式提供的。我们在Windows目录下的system32文件夹中会看到kernel32.dlluser32.dllgdi32.dllwindows的大多数API都包含在这些DLL中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作。与这些动态库相对应的导入库分别为kernel32.libuser32.libgdi32.lib

2、软件的自动更新。Windows应用的开发者常常利用动态链接库来分发软件更新。他们生成一个动态库的新版本,然后用户可以下载,并用它替代当前的版本。当然,新、旧版本动态库的输出接口(即导出函数)必须一致。下一次用户运行应用程序时,应用将自动链接和加载新的动态库。

3、软件插件技术。许多Windows应用软件都支持插件扩展方式,如IE浏览器、PhotoshopOffice等等。插件在本质上都是动态库。

4、可扩展的Web服务器。

5、每个Windows驱动程序在本质上都是动态链接库。



 

原创粉丝点击