静态库和动态库基础

来源:互联网 发布:最新免费x站地域名 编辑:程序博客网 时间:2024/06/05 19:02

一 Windows的库

程序编译一般需经预处理、编译、汇编和链接几个步骤。在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;。

库包含两种:静态库和动态库

 

1 静态库:

在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。静态库扩展名为LIB,不能被程序动态加载。

 2 动态库:

动态库又称动态链接库英文为DLL,是Dynamic Link Library的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL还有助于共享数据和资源。多个应用程序可同时访问内存中单个DLL副本的内容。DLL是一个包含可由多个程序同时使用的代码和数据的库。Windows下动态库为.dll后缀,在linux在为.so后缀。

3 动态库和静态库区别:

静态库和动态库是两种共享程序代码的方式,它们的区别是:静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。

二 静态库

 

1 静态库的特点

    1.1 目标程序的归档

    1.2 静态库的代码会被嵌入到程序当中。

1.3 程序执行时不需要静态库存在

2 C语言静态库

    2.1 创建静态库

        创建Win32静态库项目,使用*.C文件建立

        项目。

    2.2 添加静态库函数

    2.3 在程序中将静态库导入

       2.3.1 项目的Setting里设置静态库目录

       2.3.2 使用关键字 pragma

        #pragmacomment(lib, "../lib/winclib.lib")

    2.4 使用静态库提供的函数

       C语言程序中,直接使用函数即可。

3 C++语言的静态库

    3.1 创建静态库

       创建Win32静态库项目,使用*.CPP文件建立

       项目。

    3.2 添加静态库的函数

    3.3 导入静态库

       3.3.1 项目的Setting里设置

       3.3.2 使用关键字 pragma

        #pragmacomment(lib, "../lib/wincpplib.lib")

    3.4 定义库函数的原形

       int CPP_Add( intnAdd1, int nAdd2 );

    3.5 使用库函数

    3.6 注意:

       如果在CPP文件使用C语言创建的静态库(即*.c文件生成的静态库),定义的静态库函数原形,需要增加 extern "C".

       例如:

       extern"C" int C_Add( int nAdd1, int nAdd2 );

因为c语言方式生成静态库,不会改变函数的名字,在c程序中使用静态库的时候,程序寻找库函数时会根据实际的函数名字去寻找;而c++语言方式生成静态库,会改变函数名字,在c++程序中使用静态库的时候,程序寻找库函数时,会先将函数声明时的函数名改变,用改变后的函数名去寻找库函数。所以在c++程序中使用c语言生成的静态库的时候,extern"C"对编译器提示使用C的方式来处理函数

三 动态库

 

 1 动态库的好处

    1.1 可以提供模块化的方式,方便协调开发。

    1.2 对源代码保护

    1.3 减小可执行文件的大小

    1.4 提高代码的重用率

   

 2 动态库的创建和基本使用方法

    2.1 动态库的创建

    2.2 加载动态库

    2.3 获取并使用库函数、变量或类

2.4 释放动态库

3 动态库的函数

    3.1 创建

           3.1.1 创建DLL的项目

              使用Win32 DLL项目,创建DLL,添加

              相应的文件。

           3.1.2 增加动态库函数

           3.1.3 导出动态库函数

动态库导出主要有两种方式:1__declspec(dllexport),2DEF文件导出

             3.1.3.1 使用__declspec(dllexport)方式

                在函数前增加这个关键字,例如

                __declspec(dllexport) int Dll_Add()

        3.1.3.2 增加 extern "C"方式,

           extern"C" __declspec(dllexport)

           C语言方式导出函数(该动态库供c程序使用时,需要以此方式导出)

        3.1.3.3 使用DEF文件导出

                增加扩展名为DEF的文件到项目中.

                DEF文件中添加导出定义.

                 LIBRARY dllfunc.dll //导出库

           EXPORTS             //导出表

                     Dll_Mul     @1      //导出函数

                     Dll_Div      @2

        3.2 使用

使用动态库函数有两种方式:隐式链接和显式链接

      3.2.1 隐式链接

        3.2.1.1 导入LIB

          项目的Setting或者使用#pragma导入,例如:

          #pragmacomment( lib, "../lib/dllfunc.lib")

        3.2.1.2 定义函数原形

          声明一个和导出函数一致的函数定义.

          如果DLL采用extern"C"导出函数,

          需要定义extern "C"方式函数原形(前提:导入导出都是在C++程序中)

        3.2.1.3 使用函数

          直接函数即可

        3.2.1.4 补充:应用程序查找DLL的路径的顺序

          1) 查找当前应用程序的目录.

          2) 当前的工作目录

          3) 查找Windows System32的目录

          4) 查找Windows System的目录

          5) 查找Windows目录

          6) 查找环境变量PATH指定路径

 

      3.2.2 显示链接   

                            3.2.2.1加载动态库

                              HINSTANCE LoadLibrary(

                           LPCTSTR lpLibFileName);//DLL的路径

          返回加载好DLL的句柄

                            3.2.2.2定义函数原形对应的函数指针

                            3.2.2.3获取函数地址

                               FARPROC GetProcAddress(

                                     HMODULE hModule,//DLL的句柄

                                     LPCSTR lpProcName );//函数的名称

                                   返回对应函数地址

                                   注意:

                                   1对于__declspec(dllexport)导出的函数,

                                     由于函数名称发生变化,所以无法使用

                                     函数名称获取对应的函数地址,所以

                                     尽量采用隐式链接的方式.

                                   2extern "C"DEF方式导出的函数,

                                     可以正常的使用函数名称获取函数地址.

                            3.2.2.4 使用函数

                            3.2.2.5释放动态库

                               FreeLibrary

4 动态库的变量

      

         4.1 定义并导出全局变量

            4.1.1 __declspec(dllexport)导出

                                   __declspec(dllexport)int g_nValue1 = 100;

            4.1.2 DEF文件导出

               int g_nValue1 = 100;

               DEF文件的导出列表中增加

                 g_nValue1 @1 DATA

         4.2 导入LIB文件

项目的Setting或者使用#pragma导入,例如:

         #pragmacomment( lib, "../lib/dllfunc.lib")

         4.3 声明导入变量

            需要使用__declspec(dllimport)声明变量.

            extern __declspec(dllimport) intg_nValue1;

         4.4 使用变量

5 动态库的类

         5.1 创建动态库并定义类

         5.2 DLL中导出类

            在类名称前增加__declspec(dllexport)定义.

            class __declspec(dllexport) CMath

                      { ... };

         5.3 使用时导入LIB文件

         5.4 导入类

            在类名称前增加__declspec(dllimport)定义.

            class __declspec(dllimport) CMath

                      { ... };

         5.5 使用类

         5.6 关于类的导入和导出

           1) 定义一个宏,例如:

             #ifdef _DLLCLASS_DLL_

                            #define DLLCLASS_EXT__declspec(dllexport)

                            #else

                            #defineDLLCLASS_EXT __declspec(dllimport)

                            #endif//_DLLCLASS_DLL_

                2) 根据编译项目,修改_DLLCLASS_DLL_宏声明

                  对于导出类,需要定义_DLLCLASS_DLL_,

                  否则不需要定义 _DLLCLASS_DLL_

      3) 类的定义为

        classDLLCLASS_EXT CMath

        { ... };

使用_DLLCLASS_DLL_宏作为开关,减少导入导出的重复代码

6 DllMain 函数

    DLL文件入口函数.当程序加载或者释放

    动态库的时候,会自动调用这个函数.

     BOOL WINAPIDllMain(

       HINSTANCEhinstDLL,//DLL的句柄

       DWORDfdwReason,//DLL被调用的原因

       LPVOIDlpvReserved ); //保留值

     fdwReason -

      DLL_PROCESS_ATTACH 进程加载

      DLL_THREAD_ATTACH  线程加载

      DLL_THREAD_DETACH  线程卸载

      DLL_THREAD_DETACH  进程卸载

     返回值表示是否加载成功.

0 0
原创粉丝点击