当前位置: 首页 > news >正文

你所不知道的C和C++运行库

在使用VC构建项目时,经常会遇到下面的链接错误:

 

  初学者面对这些错误常常不知所错:libcmt.lib是什么东西?msvcrtd.dll又是干吗用的?在使用VC++时我们也常常对下面的运行库配置项感到疑惑,它们到底究竟是什么意思呢?甚至一些工作了很多年的程序员也对此一知半解。今天让我们来了解一下它们。
    

从C和C++运行库说起

  为了提高C语言的开发效率,C标准定义了一系列常用的函数,称为C库函数C标准仅仅定义了函数原型,并没有提供实现。因此这个任务留给了各个支持C语言标准的编译器。每个编译器通常实现了标准C的超集,称为C运行时库(C Run Time Libray) ,简称CRT对于VC++(Visual C++)编译器来说,它提供的CRT库支持C标准定义的标准C函数,同时也有一些专门针对windows系统特别设计的函数。
  与C语言类似,C++也定义了自己的标准,同时提供相关支持库,我们把它称为C++运行时库或C++标准库
  由于C++对C的兼容性,C++标准库包括了C标准库,除此之外还包括IO流和标准模板库STL。

VC++在何处实现C和C++运行库

  VC++完美的支持C和C++标准,因此也就按照C和C++的标准定义的函数原型实现了上述运行时库。为了方便有不同需求的客户的使用,VC++分别实现了动态链接库DLL版本(D:Dynamic)静态库LIB版本(T:sTatic)同时为了支持程序调试且不影响程序的性能,又分别提供了对应的调试版本。调试版本的名称在Release版本名称后添了字母d

  对于C运行时库CRT,VC6.0、VC2005、VC2008和VC2010均提供了DLL版本和LIB版本。上述各个编译器提供的LIB版的CRT库,均实现在libcmt.lib。对应的调试版名称为libcmtd.lib。

  而DLL版本名称根据编译器不同而不同,我们可以从名称上加以分辨。
  VC6.使用的CRT库的DLL版本在MSVCRT.DLL中实现, 对应调试版本为MSVCRTD.LIB。
  VC2005使用的CRT库的DLL版本在MSVCR80.DLL中实现,对应调试版本为MSVCR80.DLL。
  VC2008使用的CRT库的DLL版本在MSVCR90.DLL中实现,对应调试版本为MSVCR90D.DLL。
  VC2010使用的CRT库的DLL版本在MSVCR100.DLL中实现,对应调试版本为MSVCR100D.DLL。

  C++标准兼容C标准,但VC各版本将C++编译器使用的C标准库与C编译器使用的C运行库一起实现,它们使用相同的运行库。

  对于C++标准库中的IO流和STL,VC6.0、VC2005、VC2008和VC2010也提供了DLL版本和LIB版本。
  LIB版均实现在libcpmt.lib中,对应的调试版本为libcpmtd.lib。(p:plus)

  不同版本的编译器实现的DLL也不相同。
  VC6.使用的C++类库的 DLL版本在MSVCP60.DLL中实现, 对应调试版本为MSVCP60D.LIB。
  VC2005使用的C++类库的DLL版本在MSVCP80.DLL中实现,对应调试版本为MSVCP80.DLL。
  VC2008使用的C++类库的 DLL版本在MSVCP90.DLL中实现,对应调试版本为MSVCP90D.DLL。
  VC2010使用的C++类库的DLL版本在MSVCP100.DLL中实现,对应调试版本为MSVCP100D.DLL。

  在各个版本的编译器中,我们可以通过配置选项来设置程序使用的C和C++运行时库的类型。如下图(其他版本编译器大同小异):
  
   
  MT选项:链接LIB版的C和C++运行库。在链接时就会在将C和C++运行时库集成到程序中成为程序中的代码,程序体积会变大
  MTd选项:LIB的调试版。
  MD选项:使用DLL版的C和C++运行库,这样在程序运行时会动态的加载对应的DLL,程序体积会减小,缺点是在系统没有对应DLL时程序无法运行
  MDd选项:表示使用DLL的调试版。
  在 《由使用LeakDialog时遇到的问题而引出的一些分析》 这篇文章中的实验一,使用VC6.0的默认配置没有拦截到内存泄露。其原因是VC6.0的控制台项目默认配置是静态链接CRT库(单线程版,后面会介绍)。

动态版(DLL)和静态版(LIB)C和C++运行库的优缺点

  因为静态版必须把C和C++运行库复制到目标程序中,所以产生的可执行文件会比较大。同时对于使用多个模块的大型软件来说,如果每个模块均选择静态链接C或C++运行库,在程序运行时就会存在多个运行库。在链接时也会出现重复定义的问题,如文章首第一张图所示。
  使用DLL版的C和C++运行库,程序在运行时动态的加载对应的DLL。程序体积变小,但一个很大的问题就是一旦找不到对应DLL,程序将无法运行。假设使用VC6.0并选择使用MD选项构建,那么当用户使用VC2005来使用这个DLL时很可能出现找不到MSVCRT.DLL或MSVCP60.DLL的情况。

  在这里介绍一个很好的工具:Dependency Walker,可以用来分析DLL的依赖关系,同时查看DLL导出的函数,使用方法请Google。
  使用该工具打开MSVCRT.DLL,如下图:
   
  我们可以在其中找到我们经常使用使用的C函数,如printf ,getchar,malloc等。
  打开MSVCP100.DLL,也可以找到这些C函数:
   
  在开发的过程中我们也会遇到如下图的链接错误,LIBCD.lib究竟是何方神圣呢?
 
  它其实是LIBC.lib的调试版,而LIBC.lib是只有在VC6.0才会使用的静态库,该库是CRT的单线程版,用于支持单线程版本的CRT。VC2005等更高版本的编译器已经不再提供单线程版本,转而使用多线程版的MSVCR80.DLL或libcmt.lib。

  当遇到上述符号定义冲突的链接错误时,可以选择忽略libcd.lib。

相关文章:

  • 静态库和动态库冲突
  • dll搜索顺序
  • 嵌入V8入门
  • V8编程详解
  • 代理服务器
  • sqlite加密
  • x86/x64/x86_64/i386/ia32/ia64/amd/amd64 辨析
  • 理清gcc、libc、libstdc++的关系
  • gcc/g++/clang/cl编译器
  • 深入浅出让你理解什么是LLVM
  • Ninja - chromium核心构建工具
  • depot_tools
  • 智能指针 unique_ptr 详解
  • C++11中“= delete;“的使用
  • C++Error2208:...尝试引用已删除的函数
  • @jsonView过滤属性
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 【5+】跨webview多页面 触发事件(二)
  • Babel配置的不完全指南
  • CSS 提示工具(Tooltip)
  • CSS中外联样式表代表的含义
  • Docker容器管理
  • ERLANG 网工修炼笔记 ---- UDP
  • ES6核心特性
  • extract-text-webpack-plugin用法
  • Java 最常见的 200+ 面试题:面试必备
  • JWT究竟是什么呢?
  • vue数据传递--我有特殊的实现技巧
  • Webpack 4 学习01(基础配置)
  • 初识 beanstalkd
  • 汉诺塔算法
  • 前端
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 我从编程教室毕业
  • 智能网联汽车信息安全
  • hi-nginx-1.3.4编译安装
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​虚拟化系列介绍(十)
  • #Linux(Source Insight安装及工程建立)
  • #Ubuntu(修改root信息)
  • #大学#套接字
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (function(){})()的分步解析
  • (vue)页面文件上传获取:action地址
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (三)模仿学习-Action数据的模仿
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (轉貼) UML中文FAQ (OO) (UML)
  • .Net 4.0并行库实用性演练
  • .net CHARTING图表控件下载地址
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • @ModelAttribute注解使用