-
-
[原创]Runtime运行时库在MT与MD之间的差别
-
-
[原创]Runtime运行时库在MT与MD之间的差别
运行时库提供了很多变量(包括常量),还有很多类函数,比如字符串处理、输入与输出等。它们可以被静态编译到可执行文件(EXE或DLL),也可以被动态加载。
详细的说明可参考C runtime library (CRT) reference - Microsoft Docs。关于用到的库可参考C runtime (CRT) and C++ Standard Library (STL) .lib
files。
本文重点阐述运行时库在MT和MD之间的区别。
不管编译DLL还是EXE,都可以在VS中设置运行时库。
设置路径为工程属性->Configuration Properties->C/C++->Code Generation->Runtime Library。
运行时库分4类:
其中最后带d的为Debug版本的运行时库,不带d的为Release版本的运行时库。MTd和MT的T代表静态库,MDd和MD的D代表动态库。
也就是说采用MTd或MT,运行时库会被编译进EXE或DLL里;而MDd或MD的情况下,在EXE启动或DLL被加载时,运行时库会作为DLL被动态载入。
因为DLL和EXE编译时采用MT(d)或MD(d)的结果是一样的,所以这里以EXE编译时采用MT或MD为例。
-
EXE编译时依赖了其他库,这个库是静态库(x.lib)
在EXE采取MT运行时库时,静态库(x.lib)的编译也必须是MT。因为静态库的原因,EXE只需要把自己需要的代码从静态库(x.lib)提取出来就行,不考虑静态库里的运行库。所以这种情况下EXE和静态库使用的运行时库是同一套代码,都是EXE的运行时库。
-
EXE编译时依赖了其他库,这个库是动态库(x.dll)
在EXE采取MT运行时库时,动态库(x.dll)的编译也必须是MT。因为是动态库,EXE在加载动态库时,是将其全部代码(包括一份运行时库代码)加载进了EXE进程空间,这样EXE在运行时就包含了两套运行时库代码,一个是动态库的,一个是EXE的。
注:虽然EXE和DLL会用各自的运行时库,但它们用的都是进程默认堆(PEB->ProcessHeap),不存在EXE和DLL用的堆不一致的情况(网上有说使用的堆不一样,这种说法是错误的)。
不管EXE依赖的其他库是静态库还是动态库,它们都必须采用MD来编译。这种情况下编译出来的EXE和DLL(或EXE和LIB)都依赖MD运行时库(即VCRUNTIMExx.dll、MSVCPxx.dll、ucrtbase.dll)。因为都依赖MD运行时库,所以EXE和DLL(或EXE和LIB)用的是同一套运行时库。
根据上一节的描述,这种情况下,EXE和DLL会用各自的运行时库,这时会导致一种错误,如下代码所示:
1 2 3 4 5 6 7 | #include "dll.h"
int main(){
std::string str = GetString();
std::cout << str << "\n" ;
return 0;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #ifndef FUNC_TEST
#define FUNC_TEST extern "C" __declspec(dllimport)
#endif
FUNC_TEST std::string GetString();
#define FUNC_TEST extern "C" __declspec(dllexport)
#include "dll.h"
std::string GetString() {
std::string str( "hello world" );
return str;
}
|
以上代码会导致如下错误:
1 2 | __acrt_first_block == header
|
这个问题的成因请看下一节。
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
最后于 2021-8-7 13:58
被coneco编辑
,原因: