1.概论

  运行时库是程序在运行时所需要的库文件,通常运行时库是以LIB或DLL形式提供的。C运行时库诞生于20世纪70年代,当时的程序世界还很单纯,应用程序都是单线程的,多任务或多线程机制在此时还属于新观念。所以这个时期的C运行时库都是单线程的。

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

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

  (1)类似errno的全局变量,每个线程单独设置一个;

  这样从每个线程中可以获取正确的错误信息。

  (2)多线程库中的数据结构以同步机制加以保护。

  这样可以避免访问时候的冲突。

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

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) msvert.lib
Debug multiThread(dynamic link) msvertd.lib

  2.C运行时库的作用

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

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

  不采用宽字符集的控制台程序的入口点为mainCRTStartup(void)。下面我们以该函数为例来分析运行时库究竟为我们添加了怎样的入口程序。这个函数在crt0.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语言运行时库和应用程序才能正常地工作起来。

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

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

 3.各种C运行时库的区别

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

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

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

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

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

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

  /MDd、 /MLd 或 /MTd 选项使用 Debug runtime library(调试版本的运行时刻函数库),与/MD、 /ML 或 /MT分别对应。Debug版本的 Runtime Library 包含了调试信息,并采用了一些保护机制以帮助发现错误,加强了对错误的检测,因此在运行性能方面比不上Release版本。

  下面看一个未正确使用C运行时库的控制台程序:

#include <stdio.h>
#include <afx.h>
int main()
{
 CFile file;
 CString str("I love you");
 TRY
 {
  file.Open("file.dat",CFile::modeWrite | CFile::modeCreate);
 }
 CATCH( CFileException, e )
 {
  #ifdef _DEBUG
  afxDump << "File could not be opened " << e->m_cause << "\n";
  #endif
 }
 END_CATCH

 file.Write(str,str.GetLength());
 file.Close();
}

  我们在"rebuild all"的时候发生了link错误:

nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
main.exe : fatal error LNK1120: 2 unresolved externals
Error executing cl.exe.

  发生错误的原因在于Visual C++对控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程。我们只需要在Visual C++6.0中依次点选Project->Settings->C/C++菜单和选项,在Project Options里修改编译选项即可。

C 运行时库是微软对标准C库函数的实现,因为当时考虑到许多程序都使用C编写,而这些程序都要使用标准的C库,按照以前的方式每一个程序最终都要拷贝一份标准库的实现到程序中,这样同一时刻内存中可能有许多份标准库的代码(一个程序一份),所以微软出于效率的考虑把   标准C库做为动态链接来实现,这样多个程序使用C标准库时内存中就只有一份拷贝了。(对每一个程序来说,它相当于自己拥有一份,   对于标准库中的全局变量也做了处理的,不会因为共享同一份代码而出现冲突)。   这也算是对C标准库的一个扩展吧,至于说静态链接的时候仍然把它叫做运行时库那只能说这是个习惯问题而已了。  
   
  运行时库和普通的   dll   一样,如果有程序用到了才会加载,没有程序使用的时候不会驻留内存的。话虽如此,但有多少系统的东西说不定也是用C写的,这些东西的存在就使C运行时库存在于内存中了

从字面上看,运行库是程序在运行时所需要的库文件。通常运行库是以DLL形式提供的。 Delphi和C++ Builder的运行库为.bpl文件,实际还是一个DLL。运行库中一般包括编程时常用的函数,如字符串操作、文件操作、界面等内容。不同的语言所支持的函数通常是不同的,所以使用的库也是完全不同的,这就是为什么有VB运行库、C运行库、Delphi运行库之分的原因。即使都是C++语言,也可能因为提供的函数不同,而使用不同的库。如VC++使用的运行库和C++ Builder就完全不同。
如果不使用运行库,每个程序中都会包括很多重复的代码,而使用运行库,可以大大缩小编译后的程序的大小。但另一方面,由于使用了运行库,所以在分发程序时就必须带有这些库,比较麻烦。如果在操作系统中找不到相应的运行库程序就无法运行。为了解决这个矛盾,Windows总是会带上它自己开发的软件的最新的运行库。象Windows 2000以后的版本都包括Visual Basic 5.0/6.0的库。Internet Explorer总是带有最新的Visual C++ 6.0的库。Windows XP带有Microsoft .NET 1.0(用于VB.NET和C#)的库。Visual C++、Delphi和C++ Builder允许用户选择所编译得到的程序是否依赖于运行库。而VB、FoxPro、PowerBuilder、LabWindows/CVI和 Matlab就不允许用户进行这种选择,必须依赖于运行库。

http://blog.csdn.net/daiyutage/article/details/8579771

VC++中的C运行时库浅析(控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)的更多相关文章

  1. C运行时库(C Run-time Library)详解(提供的另一个最重要的功能是为应用程序添加启动函数。Visual C++对控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)

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

  2. 目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”)。静态库是一个或者多个obj文件的打包

    前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”) ...

  3. vc下的静态链接库与动态链接库(一)

    一.静态库与动态库的区别 目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Lib ...

  4. VC++:创建,调用Win32静态链接库

    概述 DLL(Dynamic Linkable Library)动态链接库,Dll可以看作一种仓库,仓库中包含了可以直接使用的变量,函数或类. 仓库的发展史经历了"无库" ---& ...

  5. C/C++ 静态链接库(.a) 与 动态链接库(.so)

    平时我们写程序都必须 include 很多头文件,因为可以避免重复造轮子,软件大厦可不是单靠一个人就能完成的.但是你是否知道引用的那些头文件中的函数是怎么被执行的呢?这就要牵扯到链接库了! 库有两种, ...

  6. 动态链接库dll,静态链接库lib, 导入库lib

    转载地址:http://www.cnblogs.com/chio/archive/2008/08/05/1261296.html 目前以lib后缀的库有两种,一种为静态链接库(Static Libar ...

  7. 动态链接库dll,导入库lib,静态链接库lib

    目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库” ...

  8. 静态链接库(lib)、动态链接库(dll)与动态链接库的导入库(lib)

    静态链接库与动态链接库相对应.动态链接库的导入库不同于以上两种库. 1.静态链接库(lib)     程序编译一般需经编辑.编译.连接.加载和运行几个步骤.在我们的应用中,有一些公共代码是需要反复使用 ...

  9. Linux 静态链接库和动态连接库

    (0)文件夹 VMware 下安装Ubuntu的吐血经历 零基础学习Shell编程 Linux下的makefile的妙用 Linux调试神器 -- gdb 十分钟学会Python的基本类型 Linux ...

随机推荐

  1. C++学习笔记8-操作符&amp;指针

    1.  重载操作符 赋值操作符的返回类型应该与内置类型赋值运算返回的类型同样.内置类型的赋值运算返回对右操作数的引用,因此,赋值操作符也返回对同一类类型的引用.比如.Sales_item的赋值操作符能 ...

  2. oracle 之 COMMENT 分类: H2_ORACLE 2014-04-24 15:30 386人阅读 评论(0) 收藏

    http://blog.csdn.net/liguihan88/article/details/3002403 无疑注释现在都被大家接受和认可,在大家编程用的IDE中都提供或有第三方插件来支持提取注释 ...

  3. Oracle 12C R2 on Linux 7.X 单实例静默安装文档

    禁用防火墙systemctl stop firewalld.servicesystemctl disable firewalld.service 禁用SELinuxcat /etc/selinux/c ...

  4. Uncaught SyntaxError: Invalid regular expression flags(看页面源代码)

    Uncaught SyntaxError: Invalid regular expression flags(看页面源代码) 一.总结 js或者jquery方面的错误看页面源代码,一下子错误就很清晰了 ...

  5. oracle 复制表数据,复制表结构

    1.不同用户之间的表数据复制 对于在一个数据库上的两个用户A和B,假如需要把A下表old的数据复制到B下的new,请使用权限足够的用户登入sqlplus:insert into B.new(selec ...

  6. sql server操作远程数据库

    --连接远程数据库 EXEC sp_addlinkedserver '服务器ip',N'SQL Server' --登录远程服务器 EXEC sp_addlinkedsrvlogin '服务器ip', ...

  7. 修改VNC的分辨率

    http://blog.csdn.net/jlds123/article/details/9064437 有时候用VNC View打开远程linux桌面时,桌面显示不出来,只有一个灰色背景加上一个命令 ...

  8. 如何使用Name对象,包括WorkspaceNames和DatasetNames

    转自chanyinhelv原文 如何使用Name对象,包括WorkspaceNames和DatasetNames 第一原文链接 该博主还有很多有关arcgis二次开发的不错的文章. 如何使用Name对 ...

  9. Framework for Graphics Animation and Compositing Operations

    FIELD OF THE DISCLOSURE The subject matter of the present disclosure relates to a framework for hand ...

  10. Oracle数据库零散知识08 -- 逻辑备份和还原(转)

    一.介绍逻辑备份是指使用工具export将数据对象的结构和数据导出到文件的过程.逻辑恢复是指当数据库对象被误操作而损坏后使用工具import利用备份的文件把数据对象导入到数据库的过程.物理备份即可在数 ...