运行时链接方式

本文通过实例演示了/MD和/MT两种链接选项在多模块环境下堆管理的区别。/MD选项下,各模块共享运行时库,堆的申请与释放更为灵活;/MT选项下,每个模块静态链接运行时库,堆操作受限于自身模块。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在介绍入口函数之前,先介绍一下几种运行时的库(Runtime Library)以及他们对应的链接选项:


1.Multi-threaded Debug (/MTd)

这个是debug版本的多线程库,静态链接的。
2.Multi-threaded (/MT)
这是release版本的多线程库,静态链接的。


3.Multi-threaded Debug DLL (/MDd)

这是debug版本的多线程库,动态链接的。

4.Multi-threaded DLL (/MD)

这是release版本的多线程库,动态链接的。


debug版本的运行库增加了一些错误检查的代码,如:堆栈的溢出检查,基于cookie的安全检查,基于CheckStackVar的检查。这些额外的代码可以帮助检测编码中的非安全错误。因此debug版本的运行效率没有release版本高。后面的章节将详细介绍debug运行时的安全检查策略。

静态链接运行时与动态链接运行时的区别在于,静态链接会将整个运行时的代码链接到模块中(也就是说每个模块都有一份运行时的代码),而动态链接会以共享的方式被模块使用(也就是说每个模块都会共享一份运行时的代码)。这样会导致在不同的链接方式下,它们有自己需要注意的地方。

1.采用/MD选项

a.由于是动态链接运行时,那么最终生成的模块体积会很小

b.每个模块都共享一份运行时代码,那么堆的申请与释放很自由,A模块申请堆,B模块释放堆,这样是可以得。

2.采用/MT选项

a.由于是静态链接的,那么每个模块都会包含一份运行时代码,自然会增加其体积。但是这样可以在缺少运行时的系统中稳定的运行。

b.每个模块都会包含一份运行时代码,那么只能在自己的模块中释放自己申请的堆,否则会出现错误。

注意:多个模块的情况下,必须选择相同的选项,不可以混用。


以下是测试方案:

在A DLL中添加申请堆和释放堆得代码,在B DLL中添加同样的代码,并将它们以不同的链接方式生成(/MD,/MT)。

在主程序中加载这两个DLL,并分别获取它们的导出函数。


A DLL代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // A_DLL.cpp : 定义 DLL 应用程序的导出函数。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. char* MallocHeap( int n )  
  7. {  
  8.     if ( n <= 0 )  
  9.     {  
  10.         return NULL;  
  11.     }  
  12.   
  13.     char* pHeap = new char( n );  
  14.   
  15.     if ( pHeap )  
  16.     {  
  17.         return pHeap;  
  18.     }  
  19.     else  
  20.     {  
  21.         return NULL;  
  22.     }  
  23.   
  24.     return NULL;  
  25. }  
  26.   
  27.   
  28. BOOL FreeHeap( char* pHeap )  
  29. {  
  30.     if ( pHeap )  
  31.     {  
  32.         delete pHeap;  
  33.         pHeap = NULL;  
  34.   
  35.         return TRUE;  
  36.     }  
  37.     else  
  38.     {  
  39.         return FALSE;  
  40.     }  
  41.   
  42.     return FALSE;  
  43. }  

B DLL代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // B_DLL.cpp : 定义 DLL 应用程序的导出函数。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6.   
  7. char* MallocHeap( int n )  
  8. {  
  9.     if ( n <= 0 )  
  10.     {  
  11.         return NULL;  
  12.     }  
  13.   
  14.     char* pHeap = new char( n );  
  15.   
  16.     if ( pHeap )  
  17.     {  
  18.         return pHeap;  
  19.     }  
  20.     else  
  21.     {  
  22.         return NULL;  
  23.     }  
  24.   
  25.     return NULL;  
  26. }  
  27.   
  28.   
  29. BOOL FreeHeap( char* pHeap )  
  30. {  
  31.     if ( pHeap )  
  32.     {  
  33.         delete pHeap;  
  34.         pHeap = NULL;  
  35.   
  36.         return TRUE;  
  37.     }  
  38.     else  
  39.     {  
  40.         return FALSE;  
  41.     }  
  42.   
  43.     return FALSE;  
  44. }  

主程序代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // LinkerOption.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include <windows.h>  
  6. #include <string.h>  
  7.   
  8. typedef char* ( *FunMallocHeap ) ( int );  
  9. typedef BOOL ( *FunFreeHeap ) ( char* );  
  10.   
  11. int _tmain(int argc, _TCHAR* argv[])  
  12. {  
  13.     HMODULE hDllA = ::LoadLibrary( L"A_DLL.dll" );  
  14.     HMODULE hDllB = ::LoadLibrary( L"B_DLL.dll" );  
  15.   
  16.     if ( !hDllA || !hDllB )  
  17.     {  
  18.         return 1;  
  19.     }  
  20.   
  21.     //获取DLL A中MallocHeap地址  
  22.     FunMallocHeap pMallocHeapA = NULL;  
  23.     pMallocHeapA = ( FunMallocHeap )::GetProcAddress( hDllA, "MallocHeap" );  
  24.   
  25.     //获取DLL B中MallocHeap地址  
  26.     FunMallocHeap pMallocHeapB = NULL;  
  27.     pMallocHeapB = ( FunMallocHeap )::GetProcAddress( hDllB, "MallocHeap" );  
  28.   
  29.     if ( !pMallocHeapA || !pMallocHeapB )  
  30.     {  
  31.         return 1;  
  32.     }  
  33.   
  34.   
  35.     //获取DLL A中FreeHeap地址  
  36.     FunFreeHeap pFreeHeapA = NULL;  
  37.     pFreeHeapA = ( FunFreeHeap )::GetProcAddress( hDllA, "FreeHeap" );  
  38.   
  39.     //获取DLL B中FreeHeap地址  
  40.     FunFreeHeap pFreeHeapB = NULL;  
  41.     pFreeHeapB = ( FunFreeHeap )::GetProcAddress( hDllB, "FreeHeap" );  
  42.   
  43.     if ( !pFreeHeapA || !pFreeHeapA )  
  44.     {  
  45.         return 1;  
  46.     }  
  47.   
  48.     if ( argc < 3 )  
  49.     {  
  50.         printf( "请输入参数:(A B)(A A)前者为申请模块,后者为释放模块\r\n" );  
  51.   
  52.         return 3;  
  53.     }  
  54.   
  55.     wchar_t szMallocObj[10];  
  56.     wcscpy( szMallocObj, argv[1] );  
  57.   
  58.     wchar_t szFreeObj[10];  
  59.     wcscpy( szFreeObj, argv[2] );  
  60.   
  61.     if ( wcscmp( szMallocObj, L"A") == 0 )//A模块申请  
  62.     {  
  63.         //使用A模块申请堆  
  64.         char*p = NULL;  
  65.         p = pMallocHeapA( 10 );  
  66.   
  67.         if ( wcscmp( szFreeObj, L"A") == 0 )//A模块释放  
  68.         {  
  69.             //使用A模块释放堆  
  70.             BOOL bRet = pFreeHeapA( p );  
  71.             if ( bRet )  
  72.             {  
  73.                 ::MessageBox( NULL, L"A DLL FreeHeap OK", L"Tips", MB_OK );  
  74.             }  
  75.             else  
  76.             {  
  77.                 ::MessageBox( NULL, L"A DLL FreeHeap Fail", L"Tips", MB_OK );  
  78.             }  
  79.   
  80.         }  
  81.   
  82.         if ( wcscmp( szFreeObj, L"B") == 0 )//B模块释放  
  83.         {  
  84.             //使用B模块释放堆  
  85.             BOOL bRet = pFreeHeapB( p );  
  86.             if ( bRet )  
  87.             {  
  88.                 ::MessageBox( NULL, L"B DLL FreeHeap OK", L"Tips", MB_OK );  
  89.             }  
  90.             else  
  91.             {  
  92.                 ::MessageBox( NULL, L"B DLL FreeHeap Fail", L"Tips", MB_OK );  
  93.             }  
  94.         }  
  95.     }  
  96.   
  97.   
  98.   
  99.     if ( wcscmp( szMallocObj, L"B") == 0 )//B模块申请  
  100.     {  
  101.         //使用B模块申请堆  
  102.         char*p = NULL;  
  103.         p = pMallocHeapB( 10 );  
  104.   
  105.         if ( wcscmp( szFreeObj, L"A") == 0 )//A模块释放  
  106.         {  
  107.             //使用A模块释放堆  
  108.             BOOL bRet = pFreeHeapA( p );  
  109.             if ( bRet )  
  110.             {  
  111.                 ::MessageBox( NULL, L"A DLL FreeHeap OK", L"Tips", MB_OK );  
  112.             }  
  113.             else  
  114.             {  
  115.                 ::MessageBox( NULL, L"A DLL FreeHeap Fail", L"Tips", MB_OK );  
  116.             }  
  117.   
  118.         }  
  119.   
  120.         if ( wcscmp( szFreeObj, L"B") == 0 )//B模块释放  
  121.         {  
  122.             //使用B模块释放堆  
  123.             BOOL bRet = pFreeHeapB( p );  
  124.             if ( bRet )  
  125.             {  
  126.                 ::MessageBox( NULL, L"B DLL FreeHeap OK", L"Tips", MB_OK );  
  127.             }  
  128.             else  
  129.             {  
  130.                 ::MessageBox( NULL, L"B DLL FreeHeap Fail", L"Tips", MB_OK );  
  131.             }  
  132.         }  
  133.     }  
  134.   
  135.     return 0;  
  136. }  



先使用/MD链接各个模块并运行,效果如下:

A申请A释放:




A申请B释放:




B申请B释放:




B申请A释放:





现在使用/MT方式链接,并测试如下;

A申请A释放:



A申请B释放:



B申请B释放:



B申请A释放:




可见,测试结果说明了/MD和/MT的区别所在。

下一节将详细介绍这两张不同运行时的更细节的区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值