vc编译器 msvcr.dll、msvcp.dll的含义和相关错误的处理
转自:http://blog.csdn.net/sptoor/article/details/6203376
很久没有写程式设计入门知识的相关文章了,这篇文章要来谈谈程式库 (Library) 连结,以及关于 MSVC 与 CRT 之间的种种恩怨情仇。
如果你使用的作业系统是 Linux、Mac 或其他非 Windows 平台,你可以忽略这篇文章;如果你使用的作业系统是 Windows 平台,但没有用 Microsoft Visual Studio C++(以下简称为 MSVC)软体撰写 C++ 程式的话,这篇文章对你的帮助可能很有限;但如果你的作业系统是 Windows,而且你使用的程式整合开发环境是 MSVC 软体撰写 C++ 程式的话,这篇文章应该能够帮助你釐清一些重要的基础观念。
身为程式设计者,在学习程式设计的过程中,你是否曾经遇过某些看起来不知所云的错误讯息,却不知该如何解决?例如当你快快乐乐地写完程式,并且确认所有的程式码都能成功通过编译之后,接着执行「建置方案」(Build Solution) 的步骤,结果却跑出一堆莫名其妙的错误:
LIBCMTD.lib(mlock.obj) : error LNK2005: __lock 已在 MSVCRTD.lib(MSVCR80D.dll) 中定义过了
LIBCMTD.lib(mlock.obj) : error LNK2005: __unlock 已在 MSVCRTD.lib(MSVCR80D.dll) 中定义过了
LIBCMTD.lib(crt0.obj) : error LNK2005: _mainCRTStartup 已在 MSVCRTD.lib(crtexe.obj) 中定义过了…………
LINK : warning LNK4098: 预设的程式库 ‘MSVCRTD’ 与其他使用的程式库冲突,请使用 /NODEFAULTLIB:library
LINK : warning LNK4098: 预设的程式库 ‘LIBCMTD’ 与其他使用的程式库冲突,请使用 /NODEFAULTLIB:library
D:/Workspace/CrtLibTest/Debug/CrtLibTest.exe : fatal error LNK1169: 找到有一或多个已定义的符号
以一般的情况来说,如果在你的程式专案中有使用某些由他人所撰写的第三方程式库或是开源专案的程式库,比较容易会发生上述的错误状况。从上述这些看似离奇而令人摸不着头绪的错误讯息中,我们大概可以猜测问题点应该在于 LIBCMTD.lib 与 MSVCRTD.lib 这两个程式库身上。但到底什么是 LIBCMTD.lib 和 MSVCRTD.lib?在我们的程式码中有使用这些程式库吗?
答案是肯定的。
熟悉 C 语言的程式设计者都知道,如果要使用 printf()、scanf() 或者 fopen() 等等 C 语言的基本 I/O 操作函式时,首先必须用 #include 语法将 stdio.h 这个标头档纳入我们的程式码中。藉由 stdio.h 中对这些 I/O 操作函式所做出的函式宣告 (function declaration),编译器 (Compiler) 才得以确认 printf、scanf 以及 fopen 等等都是合法可用的函式。
而当我们撰写的程式码经过编译器产出 OBJ 形式的档案之后,需要再经由连结器 (Linker) 的处理程序,将程式码中全部有使用到的函式定义 (function definition) 连结建置起来,才能够产生出最后的程式执行档。问题来了,我们知道 printf、scanf 以及 fopen 的函式宣告存在于 stdio.h 当中,但是这些傢伙的函式定义,也就是真正的实做程式码,究竟存放在什么地方呢?
在 C 语言的标准程式库中。
由 C 语言所制订的标准程式库,称之为「执行阶段程式库」,也就是 C Run-Time Library,通常可简称为 CRT。在 C 语言的标准程式库中,包含了一组常用的基础函式,例如 I/O 处理与字串操作程序等等,所以只要我们使用 C 语言撰写程式码,就一定要将编译完成后的程式码 OBJ 档,连结至 C 语言的执行阶段程式库,才能够产生出合法的 C
语言程式执行档。
而 CRT 并非只有单一一种版本存在。事实上,除了可以依「除错」与「释出」用途分成两个版本之外,两者又可分别衍生分出「静态连结」与「动态连结」两种形式:
静态连结:
- LIBCMTD.lib(除错版本)
- LIBCMT.lib
动态连结:
- MSVCRTD.lib(除错版本)
- MSVCRT.lib
虽然这四个 CRT 版本的用途与使用方式各不相同,但却有个共通的特点,就是它们都是满足执行绪安全需求,可在多执行绪程式码中安全使用的程式库版本。事实上,在过去 MSVC 6 的版本中,本来还有另外两个 LIBCD.lib(除错版本)与 LIBC.lib 程式库,是专门给单执行绪程式使用的 CRT 版本,但是这两个选项自 MSVC 2005 开始就从设定选项中被删除掉了,所以现在大多数程式设计者使用的都是多执行绪的 CRT
版本。
在程式库连结 (library linking) 的行为中,静态连结和动态连结的分别,在于使用静态连结时,会直接将程式库的函式定义嵌入执行档之中,而使用动态连结时,程式库的函式定义则存在于另外的独立档案,通常是 DLL 格式的档案中,然后与程式执行档一同发佈给使用者。因此在档案的尺寸上,使用动态连结的执行档档案,通常会比使用静态连结的执行档档案来得更小一些。
使用动态连结 CRT 版本的好处,是能够将经常使用到的标准程式库们独立出来,放在 Windows 的系统资料夹中,以减少我们建置出来的执行档档案尺寸。但反过来说,使用动态连结 CRT 版本的缺点也在于这些与执行档相依为命的 DLL 档案上。举例来说,如果程式以 MSVC 2005 建置出 Debug 组态的执行档,则此执行档需要有 msvcr80d.dll 存在才能顺利执行;如果是 Release 组态,则相依于 msvcr80.dll。但是如果你把相同的程式码拿到
MSVC 2008 上建置,产生出来的执行档则相依于 msvcr90d.dll 与 msvcr90.dll 两个不同的 DLL 档案。不同版本的 MSVC,都会有各自不同的相依 DLL 档案。
在 MSVC 的程式专案中,如何指定程式码要使用静态连结或者动态连结的 CRT 版本?其实很容易,只要在专案属性的「C/C++」页面中,选择「程式码产生」(Code Generation) 子页面,其中有个「执行阶段程式库」(Runtime Library) 的项目,也就是专案中用来设定 CRT 连结版本的地方。其中总共有四个选项,正好对应于上述静态连结与动态连结的四个不同程式库版本。
- 多执行绪侦错 (/MTd):对应 LIBCMTD.lib
- 多执行绪 (/MT):对应 LIBCMT.lib
- 多执行绪侦错 DLL (/MDd):对应 MSVCRTD.lib
- 多执行绪 DLL (/MD):对应 MSVCRT.lib
如果你没有做任何设定就开始建置程式的话,MSVC 的预设选项则会使用动态连结的版本。
C Runtime Library
请注意,以上只是单纯 C 语言的程式库而没有包含 C++ 语言在内。如果你的程式系统中,有包含 C++ 语言的程式码的话,那又是另外一回事了。但是在专案属性的页面中,为什么找不到相关的设定选项呢?因为 MSVC 悄悄地帮程式设计者代劳处理掉了。只要在程式码中使用 #include 语法纳入任何一个 C++ 的标头档,例如 iostream 或 fstream,MSVC 就会在连结器的运作阶段中,自动帮我们连结 C++
的执行阶段程式库。而 C++ 的执行阶段程式库,同样可分为四个版本:
静态连结:
- LIBCPMTD.lib(除错版本)
- LIBCPMT.lib
动态连结:
- MSVCPRTD.lib(除错版本):执行档相依于 MSVCP90D.dll
- MSVCPRT.lib:执行档相依于 MSVCP90.dll
至于程式执行档使用的是静态连结或者动态连结的版本,就仰赖于 C 语言的版本设定选项了。举个例子来说,如果你撰写了一个 Debug 组态的 C++ 程式,并且保留专案原先预设的建置选项(动态连结),那么最终建置出来的程式执行档将会相依于 MSVCR90D.dll 以及 MSVCP90D.dll 两个 DLL 档案。如果将相同的程式以 Release 组态建置完成,则会相依于 MSVCR90.dll 以及 MSVCP90.dll 二者。
Standard C++ Library
刚学习程式设计的入门者,经常会在满心欢喜地完成一件程式作品并且传给其他人使用时,却发现不能在别人的电脑上启动程式,其实就是陷入了使用者电脑缺少 DLL 档案而无法执行程式的窘境。有三种方法可以解决这个令人困扰的问题:
- 使用者的电脑,必须先安装「Visual C++ 可转发套件」(MSVC
2008 或 MSVC
2005 )。 - 将所需的 DLL 档案,例如 MSVCR90D.dll 与 MSVCP90D.dll,直接附在程式的下载包当中。
- 以静态连结方式建置程式执行档。
当你无法确定自己的程式或别人的程式,是否相依于某些特定的 DLL 档案时,有一个非常好用的免费工具程式 Dependency Walker,可以开启
EXE 格式的执行档或者 DLL 格式的动态程式库,然后详细地条列出它们所相依的 DLL 档案。
瞭解了几种不同的 CRT 版本选项之后,回到最前面的错误讯息问题,相信各位现在应该能够很清楚地理解,原来会发生这些奇怪的错误状况,是因为程式同时连结了 LIBCMTD.lib 与 MSVCRTD.lib 所以造成函式定义版本冲突。也就是说,程式连结器已经在其中一个 CRT 的版本中找到所需的函式定义,但此时却又跳出另外一位 CRT,也给了一份相同函式的实作版本,所以连结器无法判断应该忽略谁并且选择谁。
而这个状况的发生原因,就是你的程式与程式所连结的外部程式库,使用了不同的 CRT 版本之故。例如,当你的程式使用了 Lua,自然必须连结至 Lua 的程式库 lua5.1.lib,但如果 lua5.1.lib 是以静态连结版本的 CRT 建置而成,而你的程式却是以预设选项,动态连结 CRT 来建置程式执行档的话,如此一来就会产生上述这些错误讯息了。至此,问题的答案已昭然若揭,解决方法有二种:其一是将 Lua 重新以动态连结 CRT 的方式建置出一个新的程式库,其二则是将自己的程式专案改成以静态连结
CRT 方式建置。
换个角度想,当你身为一位程式库的设计开发者,想要将自己写的东西分享给其他人,但又不想要完全开放自己撰写的程式源码时,至少可以同时提供以下四种版本的程式库,以妥善满足使用者的各种不同需求:
- Debug:动态连结除错版本
- Release:动态连结版本
- Debug_Static:静态连结除错版本
- Release_Static:静态连结版本
然而,有时候世界并不会运作得如此理想。在某些特殊的状况下,当我们使用他人所写的第三方程式库时,有时可能只拿得到其中某个特定的版本,例如 Release_Static 版本时,就很有可能会遇到程式库冲突的错误情形。此时就需要视专案的实际需求而定,可以在专案属性中指定「忽略特定程式库」(Ignore Specific Library) 这个选项,让程式码连结器忽略某些程式库,以此化解动静程式库或新旧程式库之间的恩怨冲突。
小测验:你所撰写的程式,必须连结某个以静态多执行绪 (/MT) CRT 建置而成的程式库。如果你的程式在 Debug 组态下以多执行绪侦错 (/MTd) 选项建置,是否会产生冲突?如果你的程式在 Release 组态下以多执行绪 (/MT) 选项建置,是否会产生冲突?是的话,应该如何解决?
上面的方法还是不行!会出现其他问题的。
以下是我摸索出的最新的解决方法:
首先,所有的lib文件,使用/MTd或/MT编译。Debug调试模式使用/MTd,Release模式使用/MT。
然后,在自己的程序中也使用/MTd或/MT编译。这样就不会出问题了。
三种编译链接库的方式:
(1)连接Windows库。针对Win32 API编写的应用程序,上面的方法可能带来新问题,可以忽略libcmt.lib库,即可。如果还有其他问题,再忽略相应的库。
(2)MFC静态链接。上面的方法就是针对这种链接方式的,所以没问题。
(3)MFC动态链接。没有试过,应该和(1)类似。
最后补充:如果还不行,直接加入/force:multiple编译参数吧。这次之所以没有使用它,也是为了严谨起见
vc编译器 msvcr.dll、msvcp.dll的含义和相关错误的处理的更多相关文章
- 在VC中创建并调用DLL
转自:http://express.ruanko.com/ruanko-express_45/technologyexchange6.html 一.DLL简介 1.什么是DLL? 动态链接库英文为DL ...
- c++builder调用VC的dll以及VC调用c++builder的dll
解析__cdecl,__fastcall, __stdcall 的不同:在函数调用过程中,会使用堆栈,这三个表示不同的堆栈调用方式和释放方式. 比如说__cdecl,它是标准的c方法的堆栈调用方式,就 ...
- 让VC编译出来的程序不依赖于msvcr80.dll/msvcr90.dll/msvcr100.dll等文件
---转载:http://hi.baidu.com/liu_haitao/item/e2157ac3a3c32a0bc610b253 让VC编译出来的程序不依赖于msvcr80.dll/msvcr90 ...
- "无法加载 DLL“oramts.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。" —— 的解决方法
Oramts.dll 文件公开登记 Oracle 连接所涉及到在通过 Microsoft 分布式事务处理协调器 (MSDTC) 启动的事务中的公共 API. 在事务处理环境中运行时, Syste ...
- 四种DLL:NON-MFC DLL, Regular DLL Statically/Dynamically Linked to MFC, MFC Extension DLL
参考资料: https://msdn.microsoft.com/en-us/library/30c674tx.aspx http://www.cnblogs.com/qrlozte/p/484442 ...
- PC高级语言与施耐德、罗克韦尔、台达等PLC的Modbus通讯源代码(ModbusTCP.DLL/ModbusRTU.DLL)
1.0 通讯组件概述 该类通讯组件适用于基于PC高级语言的工业自动化控制系统,用于PC与可编程控制器(PLC).智能仪表等进行数据通讯.组件采用动态链接库文件(*.DLL)的形式,在PC系统的项目工 ...
- [ASP.NET 5]终于解决:Unable to load DLL 'api-ms-win-core-localization-obsolete-l1-2-0.dll'
11月12日,惊喜地发现SqlClient(System.Data.SqlClient.dll)跨平台了(对应的nuget包包是runtime.unix.System.Data.SqlClient), ...
- win32 Dll 中添加afx.h 出现如下错误 error LNK2005: _DllMain@12 already defined
win32 Dll 中添加afx.h 出现如下错误 nafxcwd.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in ...
- 无法加载 DLL“ArcGISVersion.dll”: 找不到指定的模块
无法加载 DLL“ArcGISVersion.dll”: 找不到指定的模块.(异常来自 HRESULT:0x8007007E).
随机推荐
- cojs 简单的最近公共祖先 解题报告
我曾经自己想过每考试一次就从考试题中找找idea来出题 这次又找到了一个,先不管原来的考试题是什么 考试题中其中的一部分就是今天的这道题目啦 当时考场上自己比较傻,没有注意到有用的性质,套用了之前黑白 ...
- lintcode:两个数的和
题目 两数之和 给一个整数数组,找到两个数使得他们的和等于一个给定的数target. 你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标.注意这里下标的范围是1到n,不 ...
- lintcode 中等题:N Queens N皇后问题
题目: N皇后问题 n皇后问题是将n个皇后放置在n*n的棋盘上,皇后彼此之间不能相互攻击.<不同行,不同列,不同对角线> 给定一个整数n,返回所有不同的n皇后问题的解决方案. 每个解决方案 ...
- Protege汉字不能正常显示问题
在Protege5.0中有下面的问题: 点击uses,汉字不能正常显示. 在qq群里面问到,可以通过设置label的方式,在对类,子类命名成英语的,点击annotations,在label中设置汉字名 ...
- MD5加密算法测试
在用户注册这一块,密码加密保证客户信息安全是最重要的,在网上查询了一些资料,发现加密算法比较流行的有MD5,DES和SHA. 虽然SHA与MD5通过碰撞法被破解了,但是MD5和SHA仍被公认是安全的加 ...
- Java并发:Callable、Future和FutureTask
Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一 ...
- Swift 版本很好的卡片切换效果基于ZLSwipeableView
前言:在这篇文章你可以学到,一些基本的Swift语法, 基本UI控件闭包等. 实际的效果,比gif图的效果好很多. 卡片切换.gif 首先需要导入ZLSwipeableView pod 'ZLSwip ...
- iOS开发--即时通讯
什么是环信? 1.环信是一个第三平台,提供即时通信(IM–Instant Messaging )的服务 2.环信是在XMPP的基础上进行二次开发 3.环信在网络上传输的数据也是XML 4.使用环信,不 ...
- unigui判断浏览器内核、操作系统以及是否移动终端函数
function GetDeviceType(var OsName, BrowserName: string; var IsMobileDevice: Boolean): string; var I: ...
- PowerDesigner连接Oracle数据库建表序列号实现自动增长
原文:PowerDesigner连接Oracle数据库建表序列号实现自动增长 创建表就不说了.下面开始介绍设置自动增长列. 1 在表视图的列上创建.双击表视图,打开table properties — ...