带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑

在Windows下进行C++的开发,不可避免的要与Windows的底层库进行交互,然而VS下的一项设置MT、MTd、MD和MDd却经常让人搞迷糊,相信不少人都被他坑过,特别是你工程使用了很多第三库的时候,及容易出现各种链接问题。看一下下面这个错误提示: 
LIBCMT.lib(_file.obj) : error LNK2005: ___initstdio already defined in libc.lib(_file.obj) 
LIBCMT.lib(_file.obj) : error LNK2005: ___endstdio already defined in libc.lib(_file.obj)

有多少人被这玩意坑过,被坑过的请举脚!哈哈……

既然这里这么容易出问题,我们就有必要对其进行深入的了解,知其然且知其所以然才能万事无惧!

1. 什么是Runtime Library?

Runtime Library就是运行时库,也简称CRT(C Run Time Library)。是程序在运行时所需要的库文件,通常运行时库是以Lib或Dll形式提供的。

Windows下C Runtime Library是微软对C标准库函数的实现,这样每个程序可以直接使用C标准库的函数;后来出现了C++,于是又在C Runtime Library基础上开发了C++ Runtime Library,实现了对C++标准库的支持。因此现在Windows下的C/C++运行时库既包含子C标准库,也包含了C++标准库。如果你安装了VS2010,在安装目录下的VC\crt\src下(如我的目录是C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src)有运行时库(CRT)的源代码,这里既有C的文件(如output.c、stdio.h等),也有C++的文件(如iostream、string)。

在C Runtime Library出现之前,许多程序都使用C编写,而这些程序都要使用标准的C库,按照以前的方式每一个程序最终都要拷贝一份标准库的实现到程序中,这样同一时刻内存中可能有许多份标准库的代码(一个程序一份),所以微软出于效率的考虑把标准C库做为动态链接来实现,这样多个程序使用C标准库时内存中就只有一份拷贝了。

确切地说运行时库指的就是对这些底层的基础功能实现的动态库(Dll),运行时库和普通的Dll一样,只有程序用到了它才会被加载,没有程序使用的时候不会驻留内存的。话虽如此,但有多少系统的东西说不定也是用C写的,这些东西的存在就使C运行时库存在于内存中了,所以运行时库几乎总是需要的。虽然说运行时库应该是动态库,但习惯上我们把与动态运行时库相同代码编译出来的静态库也称为运行时库,因此VC++下的运行时库有ML、MLd、MT、MTd、MD、MD六种(这个后面会讲)。

1.1 运行时库的主要作用

  1. 提供C标准库(如memcpy、printf、malloc等)、C++标准库(STL)的支持。
  2. 应用程序添加启动函数,启动函数的主要功能为将要进行的程序初始化,对全局变量进行赋初值,加载用户程序的入口函数。

不采用宽字符集的控制台程序的入口点为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 );
}123456789101112131415161718192021

从以上代码可知,运行库在调用用户程序的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的宽字符集版。

http://www.gexing.com/tupian/t/%E9%85%92%E6%B3%89%E5%B8%82%E5%A4%A7%E5%9C%A3%E5%B9%B3%E5%8F%B0QQ82933700/good/

http://www.gexing.com/tupian/t/%E6%A1%93%E5%8F%B0%E5%8E%BF%E5%A4%A7%E5%9C%A3%E5%B9%B3%E5%8F%B0QQ82933700

http://www.gexing.com/tupian/t/%E6%97%A0%E9%94%A1%E5%B8%82%E5%A4%A7%E5%9C%A3%E6%8B%9B%E5%95%86QQ82933700/good/

http://www.gexing.com/tupian/t/%E5%95%86%E4%B8%98%E5%B8%82%E5%A4%A7%E5%9C%A3%E6%80%BB%E4%BB%A3QQ82933700

http://www.gexing.com/tupian/t/%E5%A4%A9%E5%BF%83%E5%8C%BA%E5%A4%A7%E5%9C%A3%E6%80%BB%E4%BB%A3QQ82933700/good/

http://www.gexing.com/tupian/t/%E7%8E%89%E6%BA%AA%E5%B8%82%E5%A4%A7%E5%9C%A3%E6%8B%9B%E5%95%86QQ82933700

http://www.gexing.com/tupian/t/%E6%B9%98%E6%BD%AD%E5%B8%82%E5%A4%A7%E5%9C%A3%E6%8B%9B%E5%95%86QQ82933700

http://www.gexing.com/tupian/t/%E6%B4%9B%E5%AE%81%E5%8E%BF%E5%A4%A7%E5%9C%A3%E6%8B%9B%E5%95%86QQ82933700/good/

http://www.gexing.com/tupian/t/%E5%9B%9B%E4%BC%9A%E5%B8%82%E5%A4%A7%E5%9C%A3%E5%B9%B3%E5%8F%B0QQ82933700

http://www.gexing.com/tupian/t/%E9%98%B3%E8%B0%B7%E5%8E%BF%E5%A4%A7%E5%9C%A3%E5%BD%A9%E7%A5%A8QQ82933700/good/

http://www.gexing.com/tupian/t/%E9%82%95%E5%AE%81%E5%8C%BA%E5%A4%A7%E5%9C%A3%E6%8B%9B%E5%95%86QQ82933700/good/

http://www.gexing.com/tupian/t/%E5%8C%97%E5%85%B3%E5%8C%BA%E5%A4%A7%E5%9C%A3%E5%BD%A9%E7%A5%A8QQ82933700

http://www.gexing.com/tupian/t/%E6%B8%85%E6%B2%B3%E5%8C%BA%E5%A4%A7%E5%9C%A3%E5%BD%A9%E7%A5%A8QQ82933700/good/

http://www.gexing.com/tupian/t/%E5%85%B4%E5%AE%BE%E5%8C%BA%E5%A4%A7%E5%9C%A3%E5%A8%B1%E4%B9%90QQ82933700

http://www.gexing.com/tupian/t/%E5%AE%9C%E6%98%8C%E5%B8%82%E5%A4%A7%E5%9C%A3%E5%BD%A9%E7%A5%A8QQ82933700/good/

http://www.gexing.com/tupian/t/%E9%BC%93%E6%A5%BC%E5%8C%BA%E5%A4%A7%E5%9C%A3%E5%BD%A9%E7%A5%A8QQ82933700

http://www.gexing.com/tupian/t/%E5%90%AB%E5%B1%B1%E5%8E%BF%E5%A4%A7%E5%9C%A3%E5%A8%B1%E4%B9%90QQ82933700/good/

http://www.gexing.com/tupian/t/%E5%AE%89%E5%AE%9A%E5%8C%BA%E5%A4%A7%E5%9C%A3%E6%80%BB%E4%BB%A3QQ82933700

http://www.gexing.com/tupian/t/%E4%BA%A4%E5%9F%8E%E5%8E%BF%E5%A4%A7%E5%9C%A3%E5%B9%B3%E5%8F%B0QQ82933700/good/

http://www.gexing.com/tupian/t/%E4%B8%9C%E8%BE%BD%E5%8E%BF%E5%A4%A7%E5%9C%A3%E6%80%BB%E4%BB%A3QQ82933700

http://www.gexing.com/tupian/t/%E9%9D%92%E5%8E%9F%E5%8C%BA%E5%A4%A7%E5%9C%A3%E5%B9%B3%E5%8F%B0QQ82933700/good/

时间: 2024-10-24 04:12:47

带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑的相关文章

带你玩转Visual Studio——带你高效管理代码

上一篇文章带你玩转Visual Studio--带你高效开发通过对VAssistX优秀插件的讲解,让我们掌握了快速开发C++代码的技能.然而大部分的程序都不是一个人的开发的,是由一个团队的多个人一起开发的,大型的系统还可能由多个不同的团队分包进行开发.多人进行协作开发时,代码的管理就显得及为重要,需要借助代码管理工具的辅助,这种工具又称为版本控制系统. 目前主流的版本控制系统有: CVS:是一个用于代码版本控制的自由软件,它是一个比较早出现的工具,由于它有很多自身的缺陷,现在几乎被SVN所取代了

带你玩转Visual Studio——带你发布自己的工程库

上一篇文章带你玩转Visual Studio--带你高效管理代码通过对VisualSVN优秀插件的讲解,让我们掌握了在集成开发环境VS中快捷高效地管理代码的技能.然而我们开发的程序并不总是直接地生成可执行的软件,我们可能只是开发某个大型系统的一个组件,也可能是开发某个软件的内核SDK提供给上层的应用程序调用,在开发的过程中我们也可能会用到第三方的开源库.那如果将自己的程序编译成程序库给调用方用呢?又如何在自己的程序中引用第三方库呢?这将是这篇文章要讲的内容--发布自己的工程库. 什么是程序库?

带你玩转Visual Studio——带你了解VC++各种类型的工程

上一篇文章带你玩转Visual Studio--带你新建一个工程一文中提到新建一个工程时会有很多的工程类型(图1),现在将简单介绍各种类型工程的含义和主要用途.由于这里包含的工程类型太多,有很多本人也没有接触过,有些可能理解的不太对的地方还请谅解. 图 1:New Project 理解几个概念 在开讲之前先大概理解几个概念,这是理解后面各种工程含义的基础. COM COM(Component Object Model)组件对象模型是microsoft制定的一个组件软件标准,跟unix上的CORB

转: 带你玩转Visual Studio——带你理解多字节编码与Unicode码

上一篇文章带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑帮我们理解了Windows中的各种类型C/C++运行时库及它的来龙去脉,这是C++开发中特别容易误入歧途的一个地方,我们对它进行了总结和归纳.本篇文章我们将继续讲解C++开发中容易混淆的另一个概念——多字节字符集与Unicode字符集. 多字节字符与宽字节字符 char与wchar_t 我们知道C++基本数据类型中表示字符的有两种:char.wchar_t. char叫多字节字符,一个char占一个字节

带你玩转Visual Studio——结局汇总

感谢 这一系列文章陆陆续续写了一个月,也差不多可以告一个段落了.感谢读者们一直以来对我关注和支持!现将这一系列文章在这做一个汇总,以方便大家查阅.若是初学者,建议按顺序阅读. 系列文章目录 带你玩转Visual Studio--开篇介绍 带你玩转Visual Studio--带你新建一个工程 带你玩转Visual Studio--带你了解VC++各种类型的工程 带你玩转Visual Studio--带你高效开发 带你玩转Visual Studio--带你高效管理代码 带你玩转Visual Stu

带你玩转Visual Studio——性能分析与优化

上一篇文章带你玩转Visual Studio--VC++的多线程开发讲了VC++中多线程的主要用法.多线程是提升性能和解决并发问题的有效途经.在商用程序的开发中,性能是一个重要的指标,程序的性能优化也是一个重要的工作. 找到性能瓶颈 二八法则适合很多事物:最重要的只占其中一小部分,约20%,其余80%的尽管是多数,却是次要的.在程序代码中也是一样,决定应用性能的就那20%的代码(甚至更少).因此优化实践中,我们将精力集中优化那20%最耗时的代码上,这那20%的代码就是程序的性能瓶颈,主要针对这部

带你玩转Visual Studio——Property Manager的配制

从问题入手 抛出问题 在我的电脑上原本安装了VS2010专业版,现在由于项目的需要又安装了VS2015,但原来的VS2010用不了,在VS2010下编译程序时报如下错误: 1>TRACKER : error TRK0002: Failed to execute command: ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64_x86\CL.exe" @C:\Users\Administ

带你玩转Visual Studio——命令行编译C/C++程序

VS构建工具介绍 我们都知道C/C++源代码要生成可执行的.exe程序,需要经过编译.链接的过程.你在VS工具中只需要选择菜单Build或按一下F5可以编译.链接.运行了,其实IDE帮我隐藏了好多的具体细节. 我先假设VS2010安装在以下目录中: C:\Program Files (x86)\Microsoft Visual Studio 10.0 打开安装目录下的VSDIR\VC\bin可以看到一系列的可执行程序.exe和批处理文件,这些就是VS2010构建.编译.链接时要用到的工具.看一下

带你玩转Visual Studio——开篇介绍

开篇之前,先唠叨几句 本人从事C++开发工作一年半,总想就C++开发方面写点东西.写什么呢?想了一下还是写点跟开发密切相关的吧,要说跟开发最密切相关的那莫过于就是开发工具了,也就是常常说的集成开发环境(IDE). 这一年多从事的是C++的跨平台开发,在Linux和Windows下都开发过,但主要还是在Windows下进行开发(一般会在Windows下开发,多个平台下编译),因为Windows下有强大好用的开发工具,那就Visual Studio. 讲述的范围 本系列博文讲述的内容为: Windo