关于 VC++ CRT 的短篇故事






3.15/5 (22投票s)
各种 CRT (ML, MT, MD) 的特性以及解决初学者经常遇到的问题的方法
什么是 CRT?
CRT 是 C 运行时库的缩写。它是一个包含所有 C 标准函数的庞大库。您最初学习 C 语言时使用的所有函数,例如 printf
、scanf
、fgets
等,都包含在这个库中。基本上,Visual C++ 有三种 CRT。它们分别是单线程 (ML)、多线程 (MT) 和多线程 DLL (MD)。这些 CRT 中的每一个都有两个版本,分别是调试版和发布版,因此在 VC++ 中严格来说有六个 CRT 库。
CRT 特性
它们制作多达六个包含相同函数的库的原因,类似于 Baskin Robbins 有超过 30 种冰淇淋。它的理念是选择最适合您条件的库。就像所有冰淇淋都有不同的味道一样,这些库也有细微的差异。表 1 显示了每个 CRT 的特性。调试 CRT 有一些额外的功能,例如断言警报、内存泄漏检测等。
表 1:CRT 特性
CRT | 库 | Characteristics |
单线程 | libc.lib libcd.lib |
它仅为单线程程序制作,并且比多线程 CRT 稍快。此 CRT 中包含的某些函数在多线程版本中无法正常运行。自 Visual Studio 2005 以来,Microsoft 就不再支持这种类型的 CRT。 |
多线程 | libcmt.lib libcmtd.lib |
此 CRT 中的所有函数在多线程环境中都是安全的。 |
多线程 DLL | msvcrt.lib msvcrtd.lib |
与多线程 CRT 相同,但 CRT 函数位于单独的 DLL 中。因此,有许多模块使用此 CRT,并且程序的总大小减小了。此 CRT 的缺点是需要将程序与 CRT DLL 一起分发。 |
如何选择 CRT
如果您的程序没有库,您只需根据其特性选择 CRT 即可。更改 CRT 的方法很简单。首先,打开项目属性对话框,然后选择 C/C++ 选项卡中的代码生成(参见图 1)。现在您可以看到“运行时库”字段。将该字段更改为您的 CRT,然后重新构建您的项目。就这些了。
图 1:项目属性对话框中的运行时库
但是,如果存在静态库或动态链接库,则选择就没那么简单了。首先,您必须知道这些库的绑定时间。静态库在编译时绑定,但动态链接库在运行时绑定。它们最终都在您程序的同一内存空间中执行。
链接静态库最常见的问题是 CRT 冲突,当程序链接的 CRT 与库使用的 CRT 不同时。由于每个 CRT 都有相同的函数,因此它们不能同时链接。此问题有两种解决方案。一种是使用程序使用的相同 CRT 重新编译所有库。另一种是在项目属性对话框中添加一个 CRT 来忽略库字段(参见图 2)。
图 2:项目属性对话框中忽略特定库
动态链接库的主要问题是 new/delete 问题。如果您的程序和 DLL 链接了多线程或单线程 CRT,则您的程序和 DLL 将使用不同的堆。因此,释放 DLL 的内存,在程序中分配内存或反之,会造成运行时错误(参见列表 1 和列表 2)。您应该使用多线程 DLL CRT 或不要在 DLL 边界之外使用 new/delete 来解决此问题。
列表 1:在 DLL 边界之外使用 New/delete 的错误代码
//CreateCar is a dll function.
Car *car = CreateCar();
delete car;
列表 2:修复的未使用 DLL 边界之外 New/delete 的代码
//CreateCar, DestroyCar is a dll function
Car *car = CreateCar();
DestroyCar(car);
结论
为了避免复杂的问题,更好的方法是使用相同的 CRT,并编写一个不在 DLL 边界之外使用 new/delete 的程序。
历史
- 2007 年 8 月 28 日 - 发布原始版本