动态链接库解析

题记:

      此文主要对windows和Linux下对动态链接库调用的一些简单说明,比如多个应用调用同一个动态链接库(后面简称DLL,希望不要误解)时,DLL是一个应用启动一个(可能描述不太恰当,但意思希望能理解)还是调用的同一个内在地址?DLL中的静态区是一个一份还是共用静态区?函数是一个一份还是共用?这些都是我们在编写DLL与调用时需要思考的地方。

  

 

正文:

      首先,我们先谈谈windows下用调用动态链接库 。我用的IDE是开源跨平台的codeblocks,然后创建一个动态链接库项目。我在里面就写了两个简单的

DLL_EXPORT函数。我在里面定义了一些静态变量和普通变量。用来测试静态变量和普通变量等是如何存储的(是共享还是各自有一个copy),这里说下最终结果吧,我会在后面把代码附上,大家可以下载。结果是,静态是各自copy一份,供各自调用,而函数等则理共享的。所以他们的函数的入口地址都是完全一样,因为是共享的。

  

  下面是动态链接库中main.h的代码

  

#ifndef __MAIN_H__
#define __MAIN_H__

#include 
<windows.h>

/*  To use this exported function of dll, include this header
 *  in your project.
 
*/

#ifdef BUILD_DLL
    
#define DLL_EXPORT __declspec(dllexport)
#else
    
#define DLL_EXPORT __declspec(dllimport)
#endif


#ifdef __cplusplus
extern "C"
{
#endif
int DLL_EXPORT Max(int a,int b);
int DLL_EXPORT StaticFuc();
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__ 


下面是main.cpp

#include "main.h"

// a sample exported function

int DLL_EXPORT Max(int a,int b)
{
    
return a>b?a:b;
}

int DLL_EXPORT  StaticFuc()
{
    
static int d=20;
    
return d++;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    
switch (fdwReason)
    {
        
case DLL_PROCESS_ATTACH:
            
// attach to process
            
// return FALSE to fail DLL load
            break;

        
case DLL_PROCESS_DETACH:
            
// detach from process
            break;

        
case DLL_THREAD_ATTACH:
            
// attach to thread
            break;

        
case DLL_THREAD_DETACH:
            
// detach from thread
            break;
    }
    
return TRUE; // succesful

} 


 下面是InvokeDLL中的main.cpp文件,用来调用动态链接库,并验证

#include <windows.h>
#include 
<stdio.h>

typedef 
int(*pMax)(int a,int b);
typedef 
int(*pStaFuc)();

int main()
{
    HINSTANCE hDLL;
    hDLL 
= LoadLibrary("D:\\cplus\\DLLDemo\\bin\\Debug\\DLLDemo.dll");
    pMax Max;
    {
        Max
=(pMax)GetProcAddress(hDLL,"Max");
        
int a = Max(0,1);
        printf(
"function address: 0x%X \n",(unsigned int)&Max);
        printf(
"%d \n",a);
    }
    pStaFuc StaFuc;
    {
        StaFuc
=(pStaFuc)GetProcAddress(hDLL,"StaticFuc");
        
int retVal = StaFuc();
        printf(
"function address: 0x%X \n",(unsigned int)&StaFuc);
        printf(
"%d \n",retVal);
    }
    FreeLibrary(hDLL);
    
return 0;

} 


下面是截图:

 

下面是同时开启三个InvokeDLL2.exe和一个InvokeDLL.exe

 

 从这个运行结果是可以看出调用动态链接库的原理。

 

Linux,

    linux下的动态链接库在/lib目录下,以.so(shared object共享对象)作后缀的文件,这就是linux系统应用的动态链接库。而静态函数库是以.a作后缀。

    首先,我建立一个名为testso.c文件,在C文件中我定义了两上函数,一个是Strlen用来获取字符串长度,另外一个是Display用来打印一行记录,代码如下:

 1 /*********************************** 
 2 Filename : testso.c
 3 Description : 
 4 Author   : Rockay.lau 
 5 Date     : 2011-07-05
 6 URL      :Http://rockay.cnblogs.com
 7 ************************************/
 8 
 9 #include <stdio.h>
10 #include <assert.h>
11 
12 int Strlen(char *pStr)
13 {
14         unsigned long len;
15         assert(NULL != pStr);
16         len=0;
17         while(*pStr++)
18         {
19                 len++;
20         }
21         return len;
22 }
23 
24 void Display()
25 {
26         printf("Hello Rockay!\n");
27 }

     代码编写完后,我们用命令生成动态链接库文件,命令如下:

     gcc -fpic -shared -o libtest.so testso.c 

     运行效果如下图:

    

 

    这里我们再写一个invoke.c的文件,这里主要用来调用前面的动态链接库,代码如下:

 1 /*********************************** 
 2 Filename : invoke.c
 3 Description : 
 4 Author   : Rockay.lau 
 5 Date     : 2011-07-05
 6 URL      :Http://rockay.cnblogs.com
 7 ************************************/
 8 
 9 #include <stdio.h>
10 #include <dlfcn.h>
11 
12 #define sofile "./libtest.so"
13 
14 int main()
15 {
16         void (*pPrintFun)(void);
17         int  (*pStrFun)(char *);
18 
19         char str[]={"rockay lau"};
20 
21         void *pdlHandle;
22         char *pszErr;
23 
24         pdlHandle=dlopen(sofile,RTLD_LAZY);
25         if(!pdlHandle)
26         {
27                 printf("Load standard object failed! \n");
28         }
29 
30         pszErr=dlerror();
31         if(pszErr!=NULL)
32         {
33                 printf("Error: %s \n",pszErr);
34         }
35 
36         pPrintFun=dlsym(pdlHandle,"Display");
37         pszErr=dlerror();
38         if(pszErr==NULL)
39         {
40                 pPrintFun();
41         }
42 
43         pStrFun=dlsym(pdlHandle,"Strlen");
44         pszErr=dlerror();
45         if(pszErr==NULL)
46         {
47                 int len=pStrFun(str);
48                 printf("string length: %d \n",len);
49         }
50 
51         return 0;
52 } 

  然后输入如下命令:

  gcc -ldl -o invoke invoke.c

  运行效果如下图:



  这样,一个简单的linux下的动态链接库调用完成,关于静态变量和函数地址调用是否与windows下相同,则留给大家去验证一下。这里就不再详细描述!

  最后,如果你写的动态链接库使用平台硬件环境比较差时,那么动态链接库尽量少用静态的东西。那样可以节省很多很多的空间。道听途说No***某某手机公司就是这样规定的。

 

 

 

posted @ 2011-07-04 17:21  Rockay.lau  阅读(2953)  评论(0编辑  收藏  举报