Windows编程MD(d)、MT(d)编译选项的区别

来源:互联网 发布:网络视频会议系统方案 编辑:程序博客网 时间:2024/05/17 00:21

1. 运行时库功能 ##

运行时库是程序在运行时所需要的库文件,通常以LIB或DLL形式提供:

C运行时库 库文件 Single thread(static link) libc.lib Debug single thread(static link) libcd.lib MultiThread(static link) libcmt.lib Debug multiThread(static link) libcmtd.lib MultiThread(dynamic link) msvcrt.lib Debug multiThread(dynamic link) msvcrtd.lib

C运行时库包含了C程序运行的最基本和最常用的函数。

C运行时库除了给我们提供必要的库函数调用之外,它提供的另一个最重要的功能是为应用程序添加启动函数。

需要强调的一点,大家所熟知的main、WinMain等函数,仅仅是入口点函数,程序在执行时,首先进入的是启动函数

C运行时库启动函数的主要功能为:
1. - 获取指向新进程的完整命令行的一个指针
2. - 获取指向新进程的环境变量的一个指针
3. - 初始化C/C++运行库的全局变量
4. - 初始化C运行库内存分配函数(malloc和calloc)和其他底层I/O例程使用的堆(heap)
5. - 调用所有全局和静态C++对象的构造函数
6. - 执行完成以上工作之后,调用应用程序的入口点函数

通常,编译器在编译代码时,会在程序的二进制文件中将启动函数编译进去,这样便可以在程序启动时进行调用。

常见的入口函数和启动函数:
WinMain – WinMainCRTStartup
wWinMain – wWinMainCRTStartup
Main – mainCRTStartup
Wmain – wmainCRTStartup
其中开头的w表示Unicode版本。

因此,在编译好一个Windows程序后,当点击exe进行执行,Windows主要做的工作有如下:
1)操作系统发起执行命令;
2)调用启动函数,初始化系统环境,初始化全局变量,初始化内存空间等等上述功能;
3)调用程序的入口函数(main、WinMain)等。
4)执行程序主体代码。

附加:想详细了解程序的执行过程的,建议自己查看《Windows核心编程》里面有一章节详细介绍。

2. 编译选项

第一部分讲到了启动函数,启动函数有多种,那么到底编译器是如何抉择那个启动函数呢?

VC带的编译器名字叫cl.exe,它有几个与标准程序库有关的选项:/ML、/MLd、/MT、/MTd、/MD、/MDd。编译时到底哪个C运行时库联入程序取决于这些编译选项,选项告诉编译器应用程序想使用什么版本的C标准程序库。

/ML对应单线程静态版的标准程序库(libc.lib);
/MT对应多线程静态版标准库(libcmt.lib),此时编译器会自动定义_MT宏;
/MD对应多线程DLL版(导入库msvcrt.lib,DLL是msvcrt.dll),编译器自动定义_MT和_DLL两个宏。

后面加d的选项都会让编译器自动多定义一个_DEBUG宏,表示要使用对应标准库的调试版,因此:

/MLd对应调试版单线程静态标准库(libcd.lib);
/MTd对应调试版多线程静态标准库(libcmtd.lib);
/MDd对应调试版多线程DLL标准库(导入库msvcrtd.lib,DLL是msvcrtd.dll)。

即:

  /ML 使用LIBC.lib创建单线程可执行文件
  /MLd 使用LIBCD.lib创建调试单线程可执行文件
  /MT 使用LIBCMT.lib创建多线程可执行文件
  /MTd 使用LIBCMTD.lib创建调试多线程可执行文件
  /MD 使用MSVCRT.lib创建多线程DLL
  /MDd 使用MSVCRTD.lib创建调试多线程DLL

说明:

  (1)静态链接的单线程库

  静态链接的单线程库只能用于单线程的应用程序,C运行时库的目标代码最终被编译在应用程序的二进制文件中。
  通过/ML编译选项可以设置Visual C++使用静态链接的单线程库。

  (2)静态链接的多线程库

  静态链接的多线程库的目标代码也最终被编译在应用程序的二进制文件中,但是它可以在多线程程序中使用。
  通过/MT编译选项可以设置Visual C++使用静态链接的多线程库。

  (3)动态链接的运行时库

  动态链接的运行时库将所有的C库函数保存在一个单独的动态链接库MSVCRTxx.DLL中,MSVCRTxx.DLL处理了多线程问题。
  使用/MD编译选项可以设置Visual C++使用动态链接的运行时库。

  /MLd、/MTd或/MDd选项使用Debug Runtime Library(调试版本的运行时刻函数库),与/ML、/MT或/MD分别对应。Debug版本的Runtime Library包含了调试信息,并采用了一些保护机制以帮助发现错误,加强了对错误的检测,因此在运行性能方面比不上Release版本。(通常在开发过程中,使用debug版本,发行时,使用Release版本,只要自己设置好编译选项,程序的执行能力是很强的

  程序运行时,很大一部分时间是在这些运行库里运行。在程序(Release版)被编译时,VC会根据编译选项(单线程、多线程或DLL)自动将相应的运行时库文件(libc.lib、libcmt.lib或Import library msvcrt.lib)链接进来。

注:修改编译选项,将/MD或/MDd改为/MT或/MTd,就实现了对VC运行时库的静态链接,在运行时就不再需要VC的dll了。

3. VS中的编译选项MD(d)、MT(d)

编译选项 附件的宏定义 静态链接的lib 说明 /MD _MT、_DLL MSVCRT.lib+MSVCRxx.DLL 多线程、Release、DLL版本的运行时库 —只能用于Release版本 /MDd _DEBUG、_MT、_DLL MSVCRTD.lib+MSVCRxx.DLL 多线程、Debug、DLL版本的运行时库 —-只能用于Debug版本 /MT _MT LIBCMT.lib 多线程、Release版本的运行时库 /MTd _DEBUG、_MT LIBCMTD.lib 多线程、Debug版本的运行时库

/MT是”multithread, static version” 意思是多线程静态的版本,定义了它后,编译器把LIBCMT.lib安置到OBJ文件中,让链接器使用LIBCMT.lib 处理外部符号。
/MD是”multithread- and DLL-specific version”,意思是多线程DLL版本,定义了它后,编译器把MSVCRT.lib安置到OBJ文件中,它连接到DLL的方式是静态链接,但实际上工作的库是MSVCRxx.DLL
即:
静态运行时库:LIBCMT.lib
动态运行时库:MSVCRT.lib +MSVCRxx.DLL

简单的说:

(1)/MD,表示运行时库由操作系统提供一个DLL,程序里不集成。

(2)/MT,表示运行时库由程序集成,程序不再需要操作系统提供运行时库DLL。

选择/MD的优势
(1)程序就不需要静态链接运行时库,可以减小软件的大小;

(2)所有的模块都采用/MD,使用的是同一个堆,不存在A堆申请,B堆释放的问题。

选择/MT的优势
有些系统可能没有程序所需要版本的运行时库,程序必须把运行时库静态链接上。

注意:多个模块,必须选择相同类型的运行时库,不要混合使用。

选择/MT需要解决的堆空间释放问题:

不同的模块各自有一份C运行时库代码,各个C运行库会有各自的堆,导致了各个模块会有各自的堆。如果在A堆中申请空间,到B堆中释放就会有崩溃,因此在模块A申请的空间,必须在模块A中释放。

0 0