动态链接库解析

题记:

      此文主要对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***某某手机公司就是这样规定的。

 

 

 

转载于:https://www.cnblogs.com/Rockay/archive/2011/07/04/dllcheck.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值