CRT运行时库

CRT运行时库

 

1)运行时库就是 C run-time library,是 C 而非 C++ 语言世界的概念:取这个名字就是因为你的 C 程序运行时需要这些库中的函数.

 

2)C 语言是所谓的“小内核”语言,就其语言本身来说很小(不多的关键字,程序流程控制,数据类型等);所以,C 语言内核开发出来之后,Dennis Ritchie 和 Brian Kernighan 就用 C 本身重写了 90% 以上的 UNIX 系统函数,并且把其中最常用的部分独立出来,形成头文件和对应的 LIBRARY,C run-time library 就是这样形成的。

 

3)随后,随着 C 语言的流行,各个 C 编译器的生产商/个体/团体都遵循老的传统,在不同平台上都有相对应的 Standard Library,但大部分实现都是与各个平台有关的。由于各个 C 编译器对 C 的支持和理解有很多分歧和微妙的差别,所以就有了 ANSI CANSI C (主观意图上)详细的规定了 C 语言各个要素的具体含义和编译器实现要求,引进了新的函数声明方式,同时订立了 Standard Library 的标准形式。所以C运行时库由编译器生产商提供。至于由其他厂商/个人/团体提供的头文件和库函数,应当称为第三方 C 运行库(Third party C run-time libraries)。

 

4)C run-time library里面含有初始化代码,还有错误处理代码(例如divide by zero处理)。你写的程序可以没有math库,程序照样运行,只是不能处理复杂的数学运算,不过如果没有了C run-time库,main()就不会被调用,exit()也不能被响应。因为C run-time library包含了C程序运行的最基本和最常用的函数。

 

 

5)到了 C++ 世界里,有另外一个概念:Standard C++ Library,它包括了上面所说的 C run-time library STL。包含 C run-time library 的原因很明显,C++ C 的超集,没有理由再重新来一个 C++ run-time library. VC针对C++ 加入的Standard C++ Library主要包括:LIBCP.LIB, LIBCPMT.LIB MSVCPRT.LIB

 

6)Windows环境下,VC提供的 C run-time library又分为动态运行时库和静态运行时库。动态运行时库主要是DLL库文件msvcrt.dll(or MSVCRTD.DLL for debug build),对应的Import library文件是MSVCRT.LIB(MSVCRTD.LIB for debug build)

静态运行时库(release)对应的主要文件是:

LIBC.LIB (Single thread static library, retail version)

LIBCMT.LIB (Multithread static library, retail version)

 

msvcrt.dll提供几千个C函数,即使是像printf这么低级的函数都在msvcrt.dll里。其实你的程序运行时,很大一部分时间时在这些运行库里运行。在你的程序(release版)被编译时,VC会根据你的编译选项(单线程、多线程或DLL)自动将相应的运行时库文件(libc.lib,libcmt.lib或Import library msvcrt.lib)链接进来。

 

编译时到底哪个C run-time library联入你的程序取决于编译选项:

/MD, /ML, /MT, /LD   (Use Run-Time Library)

你可以VC中通过以下方法设置选择哪个C run-time library联入你的程序:

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box. See the Use Run-Time Library drop-down box.

 

从程序可移植性考虑,如果两函数都可完成一种功能,选运行时库函数好,因为各个 C 编译器的生产商对标准C Run-time library提供了统一的支持.

 

 运行时库是程序在运行时所需要的库文件,通常以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运行时库除了给我们提供必要的库函数调用之外,它提供的另一个最重要的功能是为应用程序添加启动函数。

  C运行时库启动函数的主要功能为进行程序的初始化,对全局变量进行赋初值,加载用户程序的入口函数。

四、编译器链接选项
  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版本。

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

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

五、附:

  下面是MSDN关于Visual C++编译器选项的说明:

  这些选项选择单线程或多线程运行时例程,指示多线程模块是否为DLL,并选择运行时库的发布版本或调试版本。

  /MD
  使应用程序使用运行时库的多线程并特定于DLL的版本。定义_MT和_DLL,并使编译器将库名MSVCRT.lib放入.obj文件中。
  用此选项编译的应用程序静态链接到MSVCRT.lib。该库提供允许链接器解析外部引用的代码层。实际工作代码包含在MSVCR80.DLL中,该库必须在运行时对于与MSVCRT.lib链接的应用程序可用。
  当在定义了_STATIC_CPPLIB(/D_STATIC_CPPLIB)的情况下使用/MD时,它将导致应用程序与静态多线程标准C++库(libcpmt.lib)而非动态版本(msvcprt.lib)链接,同时仍通过msvcrt.lib动态链接到主CRT。

  /MDd
  定义_DEBUG、_MT和_DLL,并使应用程序使用运行时库的调试多线程并特定于DLL的版本。它还使编译器将库名MSVCRTD.lib放入.obj文件中。

  /ML
  使编译器将库名LIBC.lib放入.obj文件中,以便链接器使用LIBC.lib解析外部符号。这是编译器的默认操作。LIBC.lib不提供多线程支持。

  /MLd
  定义_DEBUG并使编译器将库名LIBCD.lib放入.obj文件中,以便链接器使用LIBCD.lib解析外部符号。LIBCD.lib不提供多线程支持。

  /MT
  使应用程序使用运行时库的多线程静态版本。定义_MT并使编译器将库名LIBCMT.lib放入.obj文件中,以便链接器使用LIBCMT.lib解析外部符号。

  /MTd
  定义_DEBUG和_MT。此选项还使编译器将库名LIBCMTD.lib放入.obj文件中,以便链接器使用LIBCMTD.lib解析外部符号。

  /LD
  创建 DLL。
  将/DLL选项传递到链接器。链接器查找DllMain函数,但并不需要该函数。如果没有编写 DllMain函数,链接器将插入返回TRUE的DllMain函数。
  链接DLL启动代码。
  如果命令行上未指定导出(.exp)文件,则创建导入库(.lib);将导入库链接到调用您的DLL的应用程序。
  将/Fe(命名EXE文件)解释为命名DLL而不是.exe文件;默认程序名成为basename.dll而不是basename.exe。
  除非显式指定/MD,否则将暗指/MT。

  /LDd
  创建调试DLL。定义_MT和_DEBUG。

  警告

  不要混合使用运行时库的静态版本和动态版本。在一个进程中有多个运行时库副本会导致问题,因为副本中的静态数据不与其他副本共享。链接器禁止在.exe文件内部既使用静态版本又使用动态版本链接,但您仍可以使用运行时库的两个(或更多)副本。例如,当与用动态(DLL)版本的运行时库链接的.exe文件一起使用时,用静态(非DLL)版本的运行时库链接的动态链接库可能导致问题。(还应该避免在一个进程中混合使用这些库的调试版本和非调试版本)。

  注:/ML、/MLd貌似已经不提供;另,LIBC.LIB,LIBCMT.LIB和MSVCRT.LIB有对应的LIBCP.LIB,LIBCPMT.LIB和MSVCPRT.LIB,作用不清楚,不知道是升级替换版本还是升级补充版本或其他功能.

 

产生

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

C运行时库就是C run-time library,诞生于20世纪70年代,是C而非C++语言世界的概念,C程序运行时需要这些库中的函数。

C 语言是所谓的“小内核”语言,就其语言本身来说很小(不多的关键字,程序流程控制,数据类型等)。所以,C语言内核开发出来之后,Dennis Ritchie和Brian Kernighan就用C本身重写了90%以上的UNIX系统函数,并且把其中最常用的部分独立出来,形成头文件和对应的LIBRARY,C运行时库就是这样形成的。

随着C语言的流行,各个C编译器的生产商/个体/团体都遵循老的传统,在不同平台上都有相对应的Standard Library,但大部分实现都是与各个平台有关的。由于各个C编译器对C的支持和理解有很多分歧和微妙的差别,所以就有了ANSI C;ANSI C(主观意图上)详细的规定了C语言各个要素的具体含义和编译器实现要求,引进了新的函数声明方式,同时订立了Standard Library的标准形式。所以C运行时库由编译器生产商提供。至于由其他厂商/个人/团体提供的头文件和库函数,应当称为第三方C运行库(Third party C run-time libraries)。

发展

到了 C++ 世界里,有另外一个概念:Standard C++ Library,它包括了上面所说的 C run-time library 和 STL。包含 C run-time library 的原因很明显,C++ 是 C 的超集,没有理由再重新来一个 C++ run-time library. VC针对C++ 加入的Standard C++ Library主要包括:LIBCP.LIB, LIBCPMT.LIB和 MSVCPRT.LIB

C运行库刚诞生的时候,程序世界还很单纯,应用程序都是单线程的,多任务或多线程机制在此时还属于新观念。所以这个时期的C运行时库都是单线程的。

随着操作系统多线程技术的发展,最初的C运行时库无法满足程序的需求,出现了严重的问题。C运行时库使用了多个全局变量(例如errno)和静态变量,这可能在多线程程序中引起冲突。假设两个线程都同时设置errno,其结果是后设置的errno会将先前的覆盖,用户得不到正确的错误信息。

因此,Visual C++提供了两种版本的C运行时库。一个版本供单线程应用程序调用,另一个版本供多线程应用程序调用。多线程运行时库与单线程运行时库有两个重大差别:

(1)类似errno的全局变量,每个线程单独设置一个。这样从每个线程中可以获取正确的错误信息。

(2)多线程库中的数据结构以同步机制加以保护。     这样可以避免访问时候的冲突。

Visual C++提供的多线程运行时库又分为静态链接库和动态链接库两类,而每一类运行时库又可再分为debug版和release版,因此Visual C++共提供了6个运行时库。如下表:(单线程和多线程都有debug版和release版;只有多线程才有静态链接库和动态链接库之分)

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运行库的作用

(1)C运行时库包含了C程序运行的最基本和最常用的函数(如memcpy、printf、malloc等)。 
(2)C运行时库除了给我们提供必要的库函数调用之外,它提供的另一个最重要的功能是为应用程序添加启动函数。C运行时库启动函数的主要功能为进行程序的初始化,对全局变量进行赋初值,加载用户程序的入口函数。

不采用宽字符集的控制台程序的入口点为mainCRTStartup(void)。下面我们以该函数为例来分析运行时库究竟为我们添加了怎样的入口程序。这个函数在crt0.c中(crt0.c是静态链接CRT,动态链接则为crtexe.c)被定义,下列的代码经过了笔者的整理和简化:

void mainCRTStartup(void) 

int mainret; 
/*获得WIN32完整的版本信息
*/ 
_osver = GetVersion(); 
_winminor = (_osver >> 8) & 0x00FF ; 
_winmajor = _osver & 0x00FF ; 
_winver = (_winmajor << 8) + _winminor; 
_osver = (_osver >> 16) & 0x00FFFF ; 
_ioinit(); /* initialize lowio */ 

_acmdln = (char *) GetCommandLineA(); /* 获得命令行信息
*/ 
_aenvptr = (char *) __crtGetEnvironmentStringsA(); /* 获得环境信息
*/ 
_setargv(); /* 设置命令行参数
*/ 
_setenvp(); /* 设置环境参数
*/ 
_cinit(); /* C数据初始化:全局变量初始化,就在这里!
*/ 
__initenv = _environ; 
mainret = main( __argc, __argv, _environ ); /*调用main函数*/ 

exit( mainret ); 
}

从以上代码可知,运行库在调用用户程序的main或WinMain函数之前,进行了一些初始化工作。初始化完成后,接着才调用了我们编写的main或WinMain函数。只有这样,我们的C语言运行时库和应用程序才能正常地工作起来。

你写的程序可以没有math库,程序照样运行,只是不能处理复杂的数学运算,不过如果没有了C run-time库,main()就不会被调用,exit()也不能被响应。

除了crt0.c外,C运行时库中还包含wcrt0.c、 wincrt0.c、wwincrt0.c三个文件用来提供初始化函数。wcrt0.c是crt0.c的宽字符集版,wincrt0.c中包含windows应用程序的入口函数,而wwincrt0.c则是wincrt0.c的宽字符集版。

Visual C++的运行时库源代码缺省情况下不被安装。如果您想查看其源代码,则需要重装Visual C++,并在重装在时选中安装运行库源代码选项。

各种C运行时库的区别

编译器链接选项:

Visual C++编译时到底哪个C运行时库联入程序取决于编译选项,选项告诉编译器应用程序想使用什么版本的C标准程序库。与标准程序库有关的选项:/ML、/MLd、/MT、/MTd、/MD、/MDd

/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)。

VC2005/VC6.0中通过以下方法设置选择哪个C run-time library联入你的程序:

VC2005 To find these options in the development environment, click Project on the Project menu, choose Properties... item. Then click the C/C++ tab, and click Code Generation in the Category box. See the Runtime Library drop-down box.

VC6.0To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box. See the Use Run-Time Library drop-down box.

各种C运行时库的区别:

(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版本。

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

注:修改编译选项,将/MD或/MDd改为/MT或/MTd,就实现了对VC运行时库的静态链接,在运行时就不再需要VC的dll了。(静态链接将目标代码直接编译在应用程序的二进制文件中,这样运行时就不需要dll了)

你可能感兴趣的:(运行)