VSc 计算程序运行时间 /MD,/MDd 和 /MT,/MTd之间的区别

运行时库说明,以及与静态库、动态库、调用程序之间的关系 - ATMCash4423的专栏 - CSDN博客
运行时库说明,以及与静态库、动态库、调用程序之间的关系
运行时库说明,以及与静态库、动态库、调用程序之间的关系
一、什么是运行时库
运行时库是程序在运行时所需&要的库文件,通常运行时库是以LIB或DLL形式提供的。运行时库除了给我们提供必要的库函数调用(如memcpy、printf、malloc等)之外,它提供的另一个最重要的功能是为应用程序添加启动函&数。&&
运行时库启动函数的主要功能为进行程序的初始化,对全局变量进行赋初值,加载用户程序的入口函数。
二、编译方式
&&&&&&&& 运行时库的编译方式有四种:
&&&&&&&&&&&&&&&&&& 动态编译:MD(release),MDd(debug)
&&&&&&&&&&&&&&&&&& 静态编译:MT(release),MTd(debug)
&&&&&&&& 此处的动态、静态编译和工程是lib、dll还是exe没有什么关系,是指定运行时库以什么方式让你的工程(lib、dll、exe)调用。如果是动态编译,则大家共同使用一个运行时库dll;如果是静态编译,编译器会把运行时库lib集成进工程(lib、dll、exe)。
&&&&&&&& 1、动态编译MD(release),MDd(debug)
&&&&&&&& MFC库和运行时库是两种库,但必须使用相同方式编译。如果使用动态编译,在没有运行环境的情况下程序会提示缺少mfc80d.dll,msvcr80d.dll,msvcp80d.dll三个动态库(vc2005,debug方式):
mfc80d.dll:MFC动态库
msvcr80d.dll:C运行时库。提供fopen,printf等C函数。
msvcp80d.dll:C++运行时库,#include
&iostream&后会要求此dll。提供fgets,STL库等。
以上三个动态库可用VC工具Depends导入来查看具体提供了什么函数。
&&&&&&&& 2、静态编译MT(release),MTd(debug)
编译器会把如下lib集成进工程:
Reusable Library
Macro(s) Defined
Single Threaded
Static MultiThread
LIBCMT.LIB
Dynamic Link (DLL)
MSVCRT.LIB
_MT and _DLL
Debug Single Threaded
Debug Static MultiThread
LIBCMTD.LIB
_DEBUG and _MT
Debug Dynamic Link (DLL)
MSVCRTD.LIB
_DEBUG, _MT, and _DLL
注:从Visual C++ 2005开始,libcp.lib和libcpd.lib(老的/ML和/MLd选项)已经被移除。通过/MT和/MTd使用libcpmt.lib和libcpmtd.lib取代。
三、与静态库、动态库、调用程序之间的关系
以各种方式编译后的对比:
链接错误,函数重定义
链接错误,函数重定义
链接错误,函数重定义
链接错误,函数重定义
&&&&&&&& 可见,使用静态库封装时需要向调用者提供4种编译版本,或者向调用者说明本静态库是什么编译方式。
注:DLL和调用程序任何一方进行静态编译后,dll内部new的内存指针在调用程序里delete时会报“堆被破坏”的错,所以两者必须同是动态编译才能dll内部new外部delete,原因是new/delete和malloc/free函数都是运行时库提供的,库内部保存了一个进程默认堆的句柄,同是动态编译时会使用同一个堆句柄,如果某一方是静态编译,双方就不会使用同一个堆句柄(静态编译后工程都会调用其本身的运行时库lib),外部delete时使用的堆句柄不一致导致提示堆被破坏。如遇到此问题可以使用HeapCreate系列函数,此系列函数会创建一个自定义堆,dll和工程都可以使用这个自定义堆。但建议不要这样做,应该谁申请的内存谁去释放。
&&&&&&&& 附一个HeapCreate系列函数的使用例子:
&&&&&&&& //创建一个自定义堆
&&&&&&&& HANDLE &myheap = HeapCreate(HEAP_GENERATE_EXCEPTIONS,);
&&&&&&&& //在自定义堆上分配内存。
&&&&&&&& int *head = (int *)HeapAlloc(myheap,HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS,sizeof(int));
&&&&&&&& //释放自定义堆上分配的内存。
&&&&&&&& HeapFree(myheap,HEAP_NO_SERIALIZE,headTemp);
&&&&&&&& //释放自定义堆
&&&&&&&& HeapDestroy(myheap);
&&&&&&&& //获取当前进程默认堆句柄,使用此句柄可直接用HeapAlloc/ HeapFree操作默认堆。
&&&&&&&& HANDLE &myheap = GetProcessHeap()
另附一个题外话:
&&&&&&&& ADO等com对象在被封装到DLL后(ado对象为全局对象,函数内没有问题),调用dll的程序一定要使用动态加载dll(自己控制dll的卸载),否则会出现程序在退出时崩溃的问题。我调试中发现程序(MFC)在退出后会先隐式调用CoUninitialize()函数关闭主线程的com库,然后才卸载DLL,此时如果dll内部有全局com对象在调用release等释放com资源的操作就会引起程序崩溃。
&&&&&&&& EXE(MFC)静态加载DLL的顺序是:
&&&&&&&& 运行时:
&&&&&&&& 1、DLL:DLL全局类对象首先被构造。
&&&&&&&& 2、DLL:初始化DLL,DllMain函数的参数ul_reason_for_call值为DLL_PROCESS_ATTACH。
&&&& 3、EXE:调用APP类构造函数。
&&&& 4、EXE:调用EXE全局类对象构造函数。
&&&& 5、EXE:执行APP类initinstance-》等一系列程序初始化操作开始,程序开始运行。
&&&& 退出时:
&&&& 1、EXE:各个类析构-》调用APP类exitInstance。
&&&& 2、EXE:EXE全局类对象析构。
&&&& 3、EXE:APP类析构。
&&&& 4、DLL:调用DllMain函数的参数ul_reason_for_call值为DLL_PROCESS_DETACH。
&&&& 5、DLL:DLL全局类对象析构。
对于com最好是每个线程的开始一次CoInitialize,退出的时候一次CoUninitialize,但如果有其他模块在调用CoUninitialize,本模块就会出问题,我又不能告诉调用者自己去CoInitialize和CoUninitialize,所以我只CoInitialize不CoUninitialize,这样不知道会有什么问题,我操作数据库会用到ADO,目前没什么问题。
BOOL APIENTRY
DllMain( HMODULE
hModule,//本dll句柄
&&&&&&&&&&&&&&&&&&&&&& DWORD&
ul_reason_for_call,//调用原因
&&&&&&&&&&&&&&&&&&&&&& LPVOID
lpReserved//保留)
&&&& switch (ul_reason_for_call)
DLL_PROCESS_ATTACH://进程第一次调用本dll时会进入。
&&&&&&&& break;
DLL_THREAD_ATTACH://每创建一个线程都会进入。
&&&&&&&& break;
DLL_THREAD_DETACH://每个线程返回时会进入,异常中断、调用TerminateThread退出的线程不会进入。
&&&&&&&& break;
DLL_PROCESS_DETACH://进程退出后会进入。
&&&&&&&& break;
&&& return
DLL动态加载
&&&& //载入dll
&&&& HINSTANCE
mydll = LoadLibrary(&D:\\mydll.dll&);
&&&& //声明dll中函数类型,类型是一个函数指针。
&&&& typedef
bool (*dllfunType)(int
&&&& //取出dll中函数地址,并赋值给一个函数指针。参数是dll句柄,参数是dll中实际的函数名称。
&&&& //函数的实际名称要看dll的函数导出方式,以C方式导出就是函数名,其他方式导出请用VC工具Depends查看。
&&&& dllfunType
dbcon = (dllfunType)GetProcAddress(mydll,
&&&& //调用函数指针。
&&&& dbcon(1,2);
&&&& //释放dll资源
&&&& FreeLibrary(mydll);
我的热门文章
即使是一小步也想与你分享2990人阅读
Programming(17)
配置Visual
Studio的C++的编译选项时,在Project的Configuration Properties-&C/C++/-&Code
Generation中,有关于Runtime
Library的设置。在Release方式下,可以设置为/MT和/MD(在Debug模式下设置的方式为/MTd和/MDd),如果该选项设置不对,
可能导致出现链接错误(***符号在某.lib中已定义之类),或者通过链接但是出现运行时错误。
此选项可参考MSDN,
一般来说,/MT是指把程序所用到的运行时库编译到project的obj文件当中,也就是在最终的输出文件中包含了链接库的信息,这样输
出文件的体积比较大,但是对运行环境的依赖性小。而/MD则是不把运行时库编译到obj文件当中,而是作为DLL文件在运行时动态的加载(而这些DLL文
件则八成儿会是由Visual Studio提供的),这样输出的文件体积会比较小,但是对运行环境的要求会比较严格,在没有对应的Visual
Studio的计算机上运行时,需要把相关的DLL文件拷贝过去。如果程序中使用了其他的.lib文件,那么这些编译生成这些.lib文
件的Runtime
Library和程序应该是相同的,即都是/MT(/MTd)或都是/MD(/MDd)。如果不同,极有可能会出现链接错误,即使链接这一步没有出错,那
么在运行时也会因为new和delete的在内存的不同位置而导致错误。Runtime
Library不同时,应该找到同一.lib文件的对应版本,或者重新从源代码中按照正确的配置编译出需要的版本。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:114171次
积分:1818
积分:1818
排名:千里之外
原创:61篇
评论:24条
(1)(3)(1)(2)(1)(2)(3)(2)(2)(2)(2)(1)(3)(1)(3)(1)(1)(2)(2)(3)(8)(17)鑷?姩鐧诲綍

我要回帖

更多关于 运行时错误1004 的文章

 

随机推荐